Skill ID
security/deceptive_ui_guard
Current manifest version
0.1.0
Proposed change
Context (v1 baseline — merged via #313)
v1 ships a deterministic, HTML-first deceptive UI scanner:
- Dual DOM vs visible-surface extraction (BeautifulSoup)
- Structural detectors: hidden styles, mislabeled CTAs, low-contrast (strict/checkout)
- Lexical KB (
kb/deception_lexicon.json) with corroboration gates
- Trust score,
agent_guidance, sanitized_excerpt, SSRF-safe optional URL fetch
- Warn-only constitution; composable with
security/prompt_injection_firewall
Known v1 gaps (documented in catalog + manifest constitution):
- Web HTML only — no render/computed-style diff
- Semantic manipulation without structural/lexical signals may not publish
- Aggressive but legitimate marketing / CMP /
sr-only accessibility text can false-positive
- Catalog has Gemini snippet only; category table in
install_extras.md omits skill in security row
- No golden HTML corpus for regression beyond inline fixtures
v2 goal: industry-grade surface-integrity guard — still deterministic core, optional render lane, dramatically lower false positives, higher recall on checkout/modal zones, test corpus that locks behavior.
v2 scope (manifest 0.2.0)
1. Render / computed-style diff lane (high priority)
Add an optional render path when inline HTML/CSS heuristics are insufficient (PhantomLint / visual-diff class of bugs):
- New optional pip extra:
security_deceptive_ui_guard_render → playwright (or document host-browser hook; Playwright preferred for CI reproducibility)
- New optional input:
render_mode: off (default), auto, force
- When enabled: load HTML in headless Chromium, extract computed visible text + bounding boxes for interactive elements
- Compare render lane vs DOM lane → publish
render_dom_divergence findings when text exists in DOM/computed tree but not in pixel-visible surface (or vice versa for overlay traps)
- Catch: external-stylesheet white-on-white,
opacity:0 without inline style, off-viewport position:absolute, zero-size click targets over CTAs
Acceptance:
- Golden fixture: external CSS hidden fee in checkout zone → publishes at
balanced
- Default path (
render_mode=off) unchanged vs v1 outputs for existing tests
2. Zone weighting & context model
Introduce deterministic zone classifier on DOM subtrees:
| Zone |
Examples |
Weight |
checkout |
#checkout, payment forms, cart totals |
Highest |
modal |
dialog, overlay, cookie wall |
High |
cmp |
consent banner containers |
Medium (allowlist-aware) |
navigation |
nav, footer links |
Low |
general |
body copy |
Baseline |
- Severity multiplier per zone (checkout mislabeled CTA > footer link)
intended_action boosts relevant zones (already partial in v1 — formalize)
- Output:
findings[].zone always populated; optional zone_summary object in outputs
3. Allowlists & false-positive reduction (critical for production)
Bundled KB additions under kb/:
allowlist_sr_only.json — patterns/classes for legitimate screen-reader-only text (sr-only, visually-hidden, WAI-ARIA boilerplate)
allowlist_cmp.json — known CMP vendor selectors + benign copy fingerprints (OneTrust, Cookiebot, generic “Accept cookies” without channel mismatch)
allowlist_seo.json — meta/JSON-LD/script hidden content not shown to users
Rules:
- Allowlisted nodes suppress channel_mismatch unless corroborated by imperative lexicon or mislabeled CTA on same control
- Document allowlist maintenance in
instructions.md (community PR path for new CMP vendors)
Acceptance: v1 false-positive fixtures (sr-only legal link, standard cookie banner) → ok at balanced
4. Expanded deception taxonomy & lexicon
Extend detectors + deception_lexicon.json:
- Pre-checked opt-in boxes (
checked default on subscribe)
- Nag /roach motel patterns (dismiss vs decline asymmetry in copy)
- Drip pricing signals (subtotal vs “due today” divergence in checkout zone)
- Fake scarcity timers (deterministic regex + structural: timer in hidden branch)
- “Continue” vs “Buy now” mislabel variants beyond
aria-label ( value vs innerText on <input type="submit"> )
Each new subtype:
- Corroboration rule documented in code comments
- At least one positive + one negative fixture
5. Golden HTML corpus & regression harness
tests/fixtures/deceptive_ui/**/*.html — categorized: clean, cmp_ok, checkout_trap, anti_agent, mislabeled_cta, render_css_hidden
- Maintainer test: parametrized scan over corpus; snapshot
status, trust_score, finding types (not full JSON — stable fields only)
- Optional:
scripts/validate_deceptive_ui_fixtures.py for contributors
Target: ≥20 fixtures, zero flaky network (HTML-only default; render fixtures gated on extra)
6. Mobile / WebView HTML profile (medium)
- Heuristics for mobile snapshots: viewport meta,
-webkit-tap-highlight, small touch targets stacked on primary CTA
- Input flag:
surface_profile: desktop (default), mobile, auto (infer from viewport meta)
- No native app OCR in v2 — HTML/WebView only
7. Session nag memory (optional, backward compatible)
Optional input session_fingerprint (string) + output session_recommendation:
- When same fingerprint rescans with escalating urgency copy across pages → publish
nag_loop finding
- Host browser agent supplies stable origin+path hash; skill remains stateless (no disk persistence)
8. Catalog & docs parity (ship with v2 code)
- Full Claude / OpenAI / DeepSeek / Ollama snippets in
docs/skills/deceptive_ui_guard.md (match prompt_injection_firewall quality)
- Fix
docs/usage/install_extras.md security category row to include both security skills
- Add browse/checkout chain paragraph to
docs/security/skill-trust-model.md
- Update
docs/usage/agent_loops.md when new demo flags exist
- Skill history row for v2 bump
9. Explicit non-goals (v2)
- No LLM-in-the-loop detection (constitution preserved)
- No auto-click, form submit, or checkout completion
- No legal ToS judgment (stay paired with
compliance/tos_evaluator)
- Native app UI / PDF / email HTML templates — defer to v3 RFC unless trivial
Architecture sketch
# guard.py lanes (v2)
# 1. dom_lane(html) -> RawSignal[]
# 2. visible_lane(html) -> RawSignal[] # v1
# 3. render_lane(html, mode) -> RawSignal[] # optional Playwright
# 4. zone_classifier(soup) -> zone map
# 5. apply_allowlists(signals, kb/) -> signals
# 6. corroborate(signals) -> findings
# 7. score(findings, zones, sensitivity) -> trust_score, status
Keep scan_surface() pure; render lane behind lazy import so default install stays lightweight.
Version & compatibility
- Bump manifest to
0.2.0
- All new inputs optional with v1 defaults
- Existing
execute({html_content, sensitivity}) contracts unchanged
- New extra is opt-in; core extra remains
security_deceptive_ui_guard = []
Test plan
- All v1 bundle + maintainer tests pass unchanged
- New parametrized golden corpus tests
- Render lane tests skipped when Playwright not installed (
pytest.importorskip)
- Allowlist regression: CMP + sr-only fixtures stay clean
python scripts/sync_extras.py --check after new extra
pytest tests/test_registry_docs.py
black --check / flake8 on touched files
Success criteria (top-tier bar)
Breaking change?
No — backward compatible
Likely touch points
Skill ID
security/deceptive_ui_guard
Current manifest version
0.1.0
Proposed change
Context (v1 baseline — merged via #313)
v1 ships a deterministic, HTML-first deceptive UI scanner:
kb/deception_lexicon.json) with corroboration gatesagent_guidance,sanitized_excerpt, SSRF-safe optional URL fetchsecurity/prompt_injection_firewallKnown v1 gaps (documented in catalog + manifest constitution):
sr-onlyaccessibility text can false-positiveinstall_extras.mdomits skill in security rowv2 goal: industry-grade surface-integrity guard — still deterministic core, optional render lane, dramatically lower false positives, higher recall on checkout/modal zones, test corpus that locks behavior.
v2 scope (manifest
0.2.0)1. Render / computed-style diff lane (high priority)
Add an optional render path when inline HTML/CSS heuristics are insufficient (PhantomLint / visual-diff class of bugs):
security_deceptive_ui_guard_render→playwright(or document host-browser hook; Playwright preferred for CI reproducibility)render_mode:off(default),auto,forcerender_dom_divergencefindings when text exists in DOM/computed tree but not in pixel-visible surface (or vice versa for overlay traps)opacity:0without inline style, off-viewportposition:absolute, zero-size click targets over CTAsAcceptance:
balancedrender_mode=off) unchanged vs v1 outputs for existing tests2. Zone weighting & context model
Introduce deterministic zone classifier on DOM subtrees:
checkout#checkout, payment forms, cart totalsmodalcmpnavigationgeneralintended_actionboosts relevant zones (already partial in v1 — formalize)findings[].zonealways populated; optionalzone_summaryobject in outputs3. Allowlists & false-positive reduction (critical for production)
Bundled KB additions under
kb/:allowlist_sr_only.json— patterns/classes for legitimate screen-reader-only text (sr-only,visually-hidden, WAI-ARIA boilerplate)allowlist_cmp.json— known CMP vendor selectors + benign copy fingerprints (OneTrust, Cookiebot, generic “Accept cookies” without channel mismatch)allowlist_seo.json— meta/JSON-LD/script hidden content not shown to usersRules:
instructions.md(community PR path for new CMP vendors)Acceptance: v1 false-positive fixtures (sr-only legal link, standard cookie banner) →
okatbalanced4. Expanded deception taxonomy & lexicon
Extend detectors +
deception_lexicon.json:checkeddefault on subscribe)aria-label(valuevs innerText on<input type="submit">)Each new subtype:
5. Golden HTML corpus & regression harness
tests/fixtures/deceptive_ui/**/*.html— categorized: clean, cmp_ok, checkout_trap, anti_agent, mislabeled_cta, render_css_hiddenstatus,trust_score, finding types (not full JSON — stable fields only)scripts/validate_deceptive_ui_fixtures.pyfor contributorsTarget: ≥20 fixtures, zero flaky network (HTML-only default; render fixtures gated on extra)
6. Mobile / WebView HTML profile (medium)
-webkit-tap-highlight, small touch targets stacked on primary CTAsurface_profile:desktop(default),mobile,auto(infer from viewport meta)7. Session nag memory (optional, backward compatible)
Optional input
session_fingerprint(string) + outputsession_recommendation:nag_loopfinding8. Catalog & docs parity (ship with v2 code)
docs/skills/deceptive_ui_guard.md(matchprompt_injection_firewallquality)docs/usage/install_extras.mdsecurity category row to include both security skillsdocs/security/skill-trust-model.mddocs/usage/agent_loops.mdwhen new demo flags exist9. Explicit non-goals (v2)
compliance/tos_evaluator)Architecture sketch
Keep
scan_surface()pure; render lane behind lazy import so default install stays lightweight.Version & compatibility
0.2.0execute({html_content, sensitivity})contracts unchangedsecurity_deceptive_ui_guard = []Test plan
pytest.importorskip)python scripts/sync_extras.py --checkafter new extrapytest tests/test_registry_docs.pyblack --check/flake8on touched filesSuccess criteria (top-tier bar)
okatbalancedBreaking change?
No — backward compatible
Likely touch points