fix(output): 19 quadratic regex runs on the output path, worst ~5.7h at the cap
The output gate claimed LLM10 self-safety on the grounds that its patterns have no nested quantifiers. True, and irrelevant: nesting is not what makes these blow up. A run in front of a REQUIRED literal, reachable from a short anchor, is enough -- crafted input repeats the anchor and never supplies the literal, so every start position rescans the tail. Quadratic, not exponential, and the max_scan_chars cap does not help: it bounds the input, and quadratic work on a bounded input is still hours. Measured, not argued. `<a:` x 100_000 took 23.4s in AUTOLINK_RE alone; the composed gate on that payload took 458.7s, extrapolating to ~5.7 hours at the 1_000_000-char input the gate itself accepts. Size-matched ordinary prose runs 0.31s, so the separation is 18x-660x -- unlike the blob in the neighbouring test, which is the *faster* side of prose and never exercised backtracking. Two fixes, chosen per pattern rather than uniformly: - active_content + lexicon JSON (15 runs): exclude the character that opens the pattern's own anchor (`[` for markdown, `<` for tags), so a run cannot reach past the next start position and the per-start costs telescope. Verified to cost no recall: long URLs, long alt text, and `<` inside a quoted attribute all still match. Bounding instead would have been linear too but wrong here -- the content is attacker-controlled, so padding past a bound would be a one-line bypass of the EchoLeak class this table exists to catch. - connstr egress (4 runs): bound the password at MAX_CONNSTR_VALUE. The exclusion fix is unavailable -- the anchor character is `/` and passwords containing `/` are the common case (measured: they match today). The residual miss is a credential over 256 chars; a token that long is still caught by egress:jwt-token. hybrid-xss:script-tag had neither option: its run is the script BODY, which may legitimately contain `<`. It now matches the opening tag and drops the `</script>` requirement. That also closes a fail-open -- `<script>alert(1)` unclosed was silently missed -- at the cost of flagging prose that merely mentions `<script>`, now documented. Found by the composed-gate test staying red after every individual scanner was already linear: the lexicon's six html-obfuscation patterns were the remaining 813x. A per-scanner test alone would have shipped that. 662 passed (was 642), and faster than before the fix.
This commit is contained in:
parent
8deca93ee1
commit
cff043787d
10 changed files with 220 additions and 30 deletions
|
|
@ -236,7 +236,7 @@
|
|||
},
|
||||
{
|
||||
"id": "html-obfuscation:display-none",
|
||||
"regex": "<[^>]+style\\s*=\\s*\"[^\"]*display\\s*:\\s*none[^\"]*\"[^>]*>",
|
||||
"regex": "<[^><]+style\\s*=\\s*\"[^\"]*display\\s*:\\s*none[^\"]*\"[^><]*>",
|
||||
"flags": "i",
|
||||
"severity": "high",
|
||||
"owasp": "LLM01",
|
||||
|
|
@ -244,7 +244,7 @@
|
|||
},
|
||||
{
|
||||
"id": "html-obfuscation:visibility-hidden",
|
||||
"regex": "<[^>]+style\\s*=\\s*\"[^\"]*visibility\\s*:\\s*hidden[^\"]*\"[^>]*>",
|
||||
"regex": "<[^><]+style\\s*=\\s*\"[^\"]*visibility\\s*:\\s*hidden[^\"]*\"[^><]*>",
|
||||
"flags": "i",
|
||||
"severity": "high",
|
||||
"owasp": "LLM01",
|
||||
|
|
@ -252,7 +252,7 @@
|
|||
},
|
||||
{
|
||||
"id": "html-obfuscation:offscreen",
|
||||
"regex": "<[^>]+style\\s*=\\s*\"[^\"]*position\\s*:\\s*absolute[^\"]*-\\d{3,}px[^\"]*\"[^>]*>",
|
||||
"regex": "<[^><]+style\\s*=\\s*\"[^\"]*position\\s*:\\s*absolute[^\"]*-\\d{3,}px[^\"]*\"[^><]*>",
|
||||
"flags": "i",
|
||||
"severity": "high",
|
||||
"owasp": "LLM01",
|
||||
|
|
@ -260,7 +260,7 @@
|
|||
},
|
||||
{
|
||||
"id": "html-obfuscation:zero-font",
|
||||
"regex": "<[^>]+style\\s*=\\s*\"[^\"]*font-size\\s*:\\s*0[^\"]*\"[^>]*>",
|
||||
"regex": "<[^><]+style\\s*=\\s*\"[^\"]*font-size\\s*:\\s*0[^\"]*\"[^><]*>",
|
||||
"flags": "i",
|
||||
"severity": "high",
|
||||
"owasp": "LLM01",
|
||||
|
|
@ -268,7 +268,7 @@
|
|||
},
|
||||
{
|
||||
"id": "html-obfuscation:zero-opacity",
|
||||
"regex": "<[^>]+style\\s*=\\s*\"[^\"]*opacity\\s*:\\s*0[^\"]*\"[^>]*>",
|
||||
"regex": "<[^><]+style\\s*=\\s*\"[^\"]*opacity\\s*:\\s*0[^\"]*\"[^><]*>",
|
||||
"flags": "i",
|
||||
"severity": "high",
|
||||
"owasp": "LLM01",
|
||||
|
|
@ -276,7 +276,7 @@
|
|||
},
|
||||
{
|
||||
"id": "html-obfuscation:zero-size-overflow",
|
||||
"regex": "<[^>]+style\\s*=\\s*\"[^\"]*(?:height|width)\\s*:\\s*0[^\"]*overflow\\s*:\\s*hidden[^\"]*\"[^>]*>",
|
||||
"regex": "<[^><]+style\\s*=\\s*\"[^\"]*(?:height|width)\\s*:\\s*0[^\"]*overflow\\s*:\\s*hidden[^\"]*\"[^><]*>",
|
||||
"flags": "i",
|
||||
"severity": "high",
|
||||
"owasp": "LLM01",
|
||||
|
|
@ -460,7 +460,7 @@
|
|||
},
|
||||
{
|
||||
"id": "hybrid-xss:script-tag",
|
||||
"regex": "<script\\b[^>]*>[\\s\\S]*?</script>",
|
||||
"regex": "<script\\b[^><]*>",
|
||||
"flags": "i",
|
||||
"severity": "high",
|
||||
"owasp": "LLM01",
|
||||
|
|
@ -484,7 +484,7 @@
|
|||
},
|
||||
{
|
||||
"id": "hybrid-xss:iframe-src",
|
||||
"regex": "<iframe\\b[^>]*src\\s*=\\s*[\"\\'][^\"\\']*(?:javascript:|data:text/html)",
|
||||
"regex": "<iframe\\b[^><]*src\\s*=\\s*[\"\\'][^\"\\']*(?:javascript:|data:text/html)",
|
||||
"flags": "i",
|
||||
"severity": "high",
|
||||
"owasp": "LLM01",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue