This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/struts.git


The following commit(s) were added to refs/heads/main by this push:
     new fade55814 docs: state output encoding by the framework's own tags as a 
§8 property
fade55814 is described below

commit fade55814b033e7f11430472ba7770a7d655f95a
Author: Lukasz Lenart <[email protected]>
AuthorDate: Sat Oct 31 09:55:49 2026 +0100

    docs: state output encoding by the framework's own tags as a §8 property
    
    §8 listed no property for the markup the bundled UI tags emit, although the
    project has CVE'd a failure of it (CVE-2011-2087), and §9's "no output
    encoding for the application's own data" read as if it disclaimed the
    case. Add §8.8: a value handed to a tag is HTML-escaped in what the tag
    writes, under every bundled theme and rendering engine, with escape and
    escapeHtmlBody as the documented opt-outs and URL-valued attributes built
    by the URL renderer. Cross-reference it from §9, add the opt-out as a §11a
    non-finding, a §14 question for the PMC and a §15 row, and note the
    revision in the header.
    
    Co-Authored-By: Claude Mythos 5.1 <[email protected]>
---
 THREAT_MODEL.md | 35 ++++++++++++++++++++++++++++++-----
 1 file changed, 30 insertions(+), 5 deletions(-)

diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md
index e2035008d..d11007a1f 100644
--- a/THREAT_MODEL.md
+++ b/THREAT_MODEL.md
@@ -29,13 +29,18 @@
   superset of the existing [`SECURITY.md`](SECURITY.md) and the published
   [Struts security guidance](https://struts.apache.org/security/); every
   load-bearing claim is tagged for provenance (see §14 for open questions).
-- **Last revised:** 2026-10-05 — re-baselined against Security Bulletins
-  **S2-075 … S2-078**, published 2026-10-05. The §12 trigger fired again on 
both counts:
+- **Last revised:** 2026-10-31 — added §8.8, output encoding by the 
framework's own
+  tags, which §8 had never stated although the project has CVE'd a failure of 
it
+  (CVE-2011-2087), and which §9's "no output encoding for the application's 
own data"
+  read as if it disclaimed; with the matching §9 cross-reference, §11a 
non-finding,
+  §14 question and §15 row. The previous revision, 2026-10-05, re-baselined 
against
+  Security Bulletins **S2-075 … S2-078**, published 2026-10-05. The §12 
trigger fired again on both counts:
   7.4.0 / 6.12.0 added default controls (§5a), and S2-076 named a consumption 
class §8.7
   did not carry — amplification, where a small input drives unbounded output. 
The pass
   also corrected the FetchMetadata / COOP / COEP interceptors from "opt-in" to 
on by
-  default in `defaultStack` (§5a, §8.5). The previous revision, 2026-08-15, 
re-baselined
-  against S2-070 … S2-074 and added §8.6 and §8.7. Bulletin-to-section map in 
§16.
+  default in `defaultStack` (§5a, §8.5). The revision before that, 2026-08-15,
+  re-baselined against S2-070 … S2-074 and added §8.6 and §8.7. 
Bulletin-to-section map
+  in §16.
 - **Version binding:** versioned with the project; a report against version *N*
   is triaged against the model as it stood at *N*. The security envelope 
changed
   materially at **7.0** (several hardening knobs flipped to secure-by-default) 
and
@@ -391,13 +396,25 @@ Struts' security work.)*
    violation.** The test is whether a bound exists, not whether the curve 
bends — see
    §3, and `SECURITY.md`'s paragraph on the linear cases. *(documented — 
S2-072,
    S2-073, S2-074, S2-076, S2-077.)*
+8. **Output encoding by the framework's own tags.** A value a UI tag renders 
into the
+   markup it emits — an attribute value, a label, a message — is HTML-escaped 
by the
+   tag, under every bundled theme and rendering engine, unless the tag's own 
documented
+   attribute turns escaping off (`escape`, `escapeHtmlBody`). URL-valued 
attributes are
+   built by the URL renderer, which URL-encodes and ampersand-escapes them 
instead. This
+   is the framework encoding *its own output*: §9's "no output encoding for the
+   application's own data" covers markup the application writes, not a value 
it hands
+   to a tag. *Violation:* a tag writing a value it was given into HTML 
unescaped, so
+   request-derived data bound to a tag attribute or body lands in the page as 
markup.
+   *Severity:* moderate (XSS through framework-emitted markup), subject to the 
bulletin
+   rating scale's mitigation clauses. *(documented — CVE-2011-2087 / WW-3597.)*
 
 ## §9 Security properties the framework does *not* provide
 
 - **No security mechanism in the general sense.** Struts provides no 
authentication,
   authorization, session security, CSRF token store, input sanitisation, or 
output
   encoding *for the application's own data* — "it is just a pure web 
framework."
-  *(documented.)*
+  *(documented.)* A value the application hands to a framework tag is the 
framework's
+  output, and §8.8 covers it.
   - *False friend:* "Struts has no built-in login/access control" is **by 
design**,
     not a vulnerability.
 - **No protection against developer anti-patterns or non-default config** — 
unsafe
@@ -473,6 +490,9 @@ authoritative list; §14 Q12.)*
 - **"Raw `${}` EL / forced OGNL eval on my request parameter is 
exploitable."** The
   application fed untrusted input to expression evaluation — documented 
anti-pattern,
   not a framework flaw.
+- **"A tag with `escape="false"` / `escapeHtmlBody="false"` writes my HTML 
unescaped."**
+  That is the documented opt-out of §8.8, chosen in the application's own 
template —
+  `BY-DESIGN`. In-model only when a tag writes a value unescaped with escaping 
left on.
 - **"Config Browser Plugin exposes internal configuration."** Dev-only 
diagnostic;
   exposing it in production is operator misconfiguration. `OUT-OF-MODEL: 
non-default-config`.
 - **"I can enumerate / pass arbitrary parameters."** Parameter binding is the 
point of
@@ -592,6 +612,10 @@ so what remains is ratifying the *wording*, not the 
substance.
   keyed on request-derived values, or only the caches and body reads bounded in
   7.3.0/6.11.0? A triager needs to know whether an unbounded structure found 
elsewhere
   in the framework is `VALID` or `VALID-HARDENING`. (§8.7.)
+- **Q-encoding.** Confirm §8.8 as a framework property: a value handed to a 
bundled UI
+  tag is HTML-escaped in the markup the tag emits, under every bundled theme 
and
+  rendering engine, and a tag that writes it raw with escaping left on is 
`VALID`
+  rather than application responsibility under §9. (§8.8, from CVE-2011-2087.)
 
 **Wave 3 — surfaces & false-friends**
 
@@ -626,6 +650,7 @@ sections:
 | Allowlist / excluded classes/packages / expression length (7.0 defaults) | 
§5a, §8.1 |
 | DMI / Strict Method Invocation | §5a, §8.3 |
 | FetchMetadata / COOP / COEP | §5a, §8.5 |
+| Tags escape what they render; `escape` / `escapeHtmlBody` are the documented 
opt-outs | §8.8, §9, §11a |
 | OGNL JSM sandbox (modern-JDK limitation) | §5a, §9 |
 | Generic DoS not accepted; non-linear-in-input philosophy | §3, §9 |
 | Unbounded reads/state are in scope even when linear | §3, §8.7, §11a |

Reply via email to