Why must sanitized match exactly in overridden methods?
← Security and Sanitization · Ref: Q663
The 'sanitized' modifier must MATCH between a method and the method it overrides (E07940). The Liskov Substitution Principle requires consistent security behavior through polymorphic dispatch.
WHY MATCH IS REQUIRED
Consider polymorphic dispatch:
handler <- getHandler() // Could be Base or Derived handler.process(userInput) // Is it sanitized or not?
If sanitized doesn't match, security depends on runtime type.
TWO FAILURE CASES
Case 1: Super has sanitized, override removes it
-> Caller expects sanitization but override skips it = vulnerability
Case 2: Super has no sanitized, override adds it
-> Caller doesn't expect data modification = LSP violation
CORRECT PATTERN
Both must agree:
defines class Base as open process() -> input as sanitized String defines class Derived extends Base override process() -> input as sanitized String // Must match!
TRAIT NOTE
Traits cannot have 'default operator ?' (E07030). When defining a trait with sanitized methods, only classes implementing the trait can have 'default operator ?'.
See Q661 for sanitized basics. See Q662 for safe copy patterns. See Q664 for increment expression restriction. See Q215 for sanitized overview.
Example
defines module qa.sanitizeddeep.overridematch defines trait <?- Trait defining sanitized contract. All implementations must preserve sanitized on the parameter. -?> InputProcessor process() as abstract -> inputText as sanitized String <- result as String? defines class <?- Base class with sanitized parameter. Subclasses MUST keep sanitized to maintain LSP. -?> BaseHandler as open handleRequest() -> requestBody as sanitized String <- response as String: "" safeCopy <- String(requestBody) response: safeCopy default operator ? <?- Correct override: sanitized matches the parent. Security behavior is consistent through polymorphism. -?> DerivedHandler extends BaseHandler override handleRequest() -> requestBody as sanitized String <- response as String: "" safeCopy <- String(requestBody) response: "Derived: " + safeCopy default operator ? <?- Trait implementation with matching sanitized. -?> SafeProcessor with trait of InputProcessor override process() -> inputText as sanitized String <- result as String: "" localCopy <- String(inputText) result: "Processed: " + localCopy default operator ? defines program OverrideMatchDemo() stdout <- Stdout() baseHandler <- BaseHandler() baseResponse <- baseHandler.handleRequest("base input") stdout.println(baseResponse) derivedHandler <- DerivedHandler() derivedResponse <- derivedHandler.handleRequest("derived input") stdout.println(derivedResponse) processor <- SafeProcessor() processResult <- processor.process("trait input") stdout.println(processResult)
Common mistakes
E50060 — String has no toUpperCase() method in EK9. Use upperCase() instead. See ek9 -h E50060 for details.
Incorrect:
baseResponse <- baseHandler.handleRequest("base input").toUpperCase()
Correct:
baseResponse <- baseHandler.handleRequest("base input")
Other ways to ask this
- What is E07940 sanitized mismatch in override?
- Can I add sanitized to an override method?
- What happens if I remove sanitized from an overriding method?
Coming from another language?
Java: no enforcement, override can change validation. Python: no enforcement. Go: no inheritance. Rust: trait implementations must match exactly. EK9: compiler enforces sanitized matching in overrides for LSP compliance.
Keywords: E07940, virtual, visitor, abstract, LSP, Liskov, open, security, sanitize, sealed, override, polymorphic, match, handler, validate, function, sanitized