feat(active-content,okf): bound the last two detection surfaces
`scan_active_content` called directly and `okf.link_graph` were the two surfaces still reading attacker-supplied text with no cap — the first reached by an adapter that wants the active-content classes alone, the second running a `findall` over every body in a bundle. Both are detection-shaped, so they truncate and flag rather than raise the way the transform surfaces do: what a detector shortens is its own coverage, not the caller's content. Truncation is only honest if it is visible, so neither goes quiet: the scanner emits `active:oversize-input` (LLM10), and `link_graph` records `(from_id, body_length)` in `LinkGraphResult.truncated` — the field that lets a caller tell "no links past here" from "no links read past here". Reached through `scan_output`, the text is already under that surface's cap and `max_scan_chars` is now passed down, so the flag is raised once, there.
This commit is contained in:
parent
0bf07295c2
commit
b90233481a
6 changed files with 111 additions and 22 deletions
|
|
@ -331,3 +331,30 @@ def test_url_defanging_survives_the_redos_fix():
|
|||
evidence = " ".join(f.evidence or "" for f in report.findings)
|
||||
assert expected in evidence, raw
|
||||
assert "http://" not in evidence and "https://" not in evidence, raw
|
||||
|
||||
|
||||
# --- self-safety (OWASP LLM10) ----------------------------------------------
|
||||
#
|
||||
# Reached through `scan_output` this detector inherits that surface's cap. Called
|
||||
# directly — the shape an adapter reaches for when it wants the active-content
|
||||
# classes alone — it had none. It is detection-shaped, so it truncates and flags
|
||||
# rather than raising the way the transform surfaces do: what a shortened scan
|
||||
# costs is coverage of the tail, not the caller's content.
|
||||
|
||||
def test_oversize_input_is_capped_and_flagged():
|
||||
big = "x" * 200 + "\n\n"
|
||||
report = scan_active_content(big, max_scan_chars=50)
|
||||
|
||||
oversize = [f for f in report.findings if "oversize" in f.label]
|
||||
assert len(oversize) == 1
|
||||
assert oversize[0].owasp == "LLM10"
|
||||
assert oversize[0].count == len(big)
|
||||
# Prefix only: the construct past the cap is not reported. This is the cost
|
||||
# the flag exists to announce, so assert it rather than assume it.
|
||||
assert not [f for f in report.findings if f.label == "active:markdown-image"]
|
||||
|
||||
|
||||
def test_input_exactly_at_the_cap_is_not_flagged():
|
||||
# The cap is the largest scanned size, not the smallest truncated one.
|
||||
report = scan_active_content("x" * 50, max_scan_chars=50)
|
||||
assert not [f for f in report.findings if "oversize" in f.label]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue