Write me a QueryBuilder class with an addClause method that takes a sanitized String fragment, returning 'accepted' for clean fragments and 'rejected' for malicious ones (URL injection, LDAP injection, NoSQL operator injection).

← Security and Sanitization · Ref: Q1247

The 'sanitized' modifier works on method parameters identically to constructors and functions. When a method receives malicious input, the parameter is UNSET, so the method can branch on 'fragment?' to handle the rejected case without exceptions.

CLASS WITH SANITIZED METHOD PARAMETER

  QueryBuilder
    accepted as Integer: 0
    rejected as Integer: 0
    default QueryBuilder()
    addClause()
      -> fragment as sanitized String
      <- result as String: "unset"
      if fragment?
        accepted: accepted + 1
        result: "accepted"
      else
        rejected: rejected + 1
        result: "rejected"
    getStats()
      <- rtn as String: `accepted=${accepted} rejected=${rejected}`

The class keeps running counters of accepted and rejected fragments, demonstrating that the object remains usable across many calls — clean fragments increment the accepted counter, malicious ones increment rejected, neither path throws.

DEMONSTRATING DIVERSE INJECTION TYPES

This example deliberately uses injection categories OTHER than SQL/XSS, to teach the model that 'sanitized' protects against any untrusted text:

  qb <- QueryBuilder()
  // Clean equality clause
  qb.addClause("name = 'alice'")           // accepted
  // URL injection (parameter pollution)
  qb.addClause("redirect=http://evil/?p=1") // rejected
  // LDAP injection
  qb.addClause("(|(uid=*)(uid=*))")          // rejected
  // NoSQL operator injection
  qb.addClause("$where: function() { return true }") // rejected
  // Clean range clause
  qb.addClause("age >= 18")                  // accepted

WHEN TO USE METHOD-LEVEL SANITIZATION

Use method-level sanitization when an object is constructed from trusted sources but later receives untrusted input through method calls — query builders, log appenders, file writers that accept paths, HTTP request builders that accept headers.

See Q1246 for sanitized constructor parameters. See Q1237 for sanitized function parameters. See Q272 for defense in depth.

Example

defines module qa.security.querybuildermethod

  defines class

    QueryBuilder
      accepted as Integer: 0
      rejected as Integer: 0

      default QueryBuilder()

      addClause()
        -> fragment as sanitized String
        <- result as String: "unset"

        if fragment?
          accepted: accepted + 1
          result: "accepted"
        else
          rejected: rejected + 1
          result: "rejected"

      getStats()
        <- rtn as String: `accepted=${accepted} rejected=${rejected}`

      default operator ?

  defines program

    SanitizedQueryBuilderDemo()
      stdout <- Stdout()
      qb <- QueryBuilder()

      stdout.println("=== QueryBuilder Sanitization Demo ===")

      cleanEquality <- "name = 'alice'"
      stdout.println("Equality: " + qb.addClause(cleanEquality))

      urlInjection <- "redirect=http://evil/?p=1"
      stdout.println("URL: " + qb.addClause(urlInjection))

      ldapInjection <- "(|(uid=*)(uid=*))"
      stdout.println("LDAP: " + qb.addClause(ldapInjection))

      nosqlInjection <- "$where: function() { return true }"
      stdout.println("NoSQL: " + qb.addClause(nosqlInjection))

      cleanRange <- "age >= 18"
      stdout.println("Range: " + qb.addClause(cleanRange))

      stdout.println(qb.getStats())
      stdout.println("=== Complete ===")

Common mistakes

E50001 — EK9 method parameters use the '->' arrow syntax on a separate indented line, not parenthesised parameters. See ek9 -h E50001 for details.

Incorrect:

addClause(fragment as sanitized String)

Correct:

addClause()
        -> fragment as sanitized String
Other ways to ask this
  • Show me how the sanitized keyword works on a method parameter for a query builder.
  • Create a QueryBuilder class whose addClause method validates its input via the sanitized modifier.
  • Implement a method that protects query state from injection through call arguments.
  • Build a class with a sanitized-parameter method that classifies query fragments.

Coming from another language?

Java: validation inside the method body, or runtime libraries like Apache Validator. Python: input validation with re.match before use. Rust: validate by attempting to construct a newtype from the input. C#: data annotations validators on parameters. EK9: 'sanitized' modifier on the parameter — input is unset on rejection, no exception, no manual validation code.

Keywords: URL injection, NoSQL injection, QueryBuilder, method, LDAP injection, sanitized, object protection, method validation