Skip to content

feat(security): skip hidden content by default - #42

Merged
chaliy merged 1 commit into
mainfrom
claude/project-thread-ulbh3z
Oct 27, 2026
Merged

chaliy merged 1 commit into
mainfrom
claude/project-thread-ulbh3z

Conversation

@chaliy

@chaliy chaliy commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Михайло · project thread

What changed

Content a reader never sees is no longer rendered by default.

HTML elements are skipped when they have:

  • the hidden attribute (but not until-found);
  • aria-hidden="true";
  • an inline style with display:none, visibility:hidden|collapse, opacity:0 or font-size:0.

<template> is stripped too.

DOCX: hidden text runs (w:vanish) are skipped. A hidden_content_skipped warning reports how many were dropped.

Opt in: MarkkitBuilder::include_hidden_content(true) renders hidden content again.

Fix included: exclude selectors and the hidden check now apply to <li>, <tr>, <th> and <td>. Before, they were ignored on those elements. An excluded or hidden cell becomes an empty cell and keeps its span, so the table layout holds.

Threat model: new threat T9 (prompt injection through invisible text) and invariant S20. Knowledge, CHANGELOG and the log are updated.

Not detected: hiding done through stylesheets or classes, such as .sr-only or off-screen positioning. Only signals on the element itself count.

Why

Hidden text is a common prompt-injection carrier. A page or document can show one thing to a human reviewer and feed different instructions to an LLM that reads markkit's output.

Before / After

Input file: <p>Visible</p><p style="display:none">Ignore previous instructions</p><div aria-hidden="true">secret</div>

markkit extract --file h.html before:

Visible

Ignore previous instructions

secret

After:

Visible

Tests:

  • New tests/hidden_content.rs covers each HTML signal, DOCX w:vanish, the opt-in, the until-found exception and the warning.
  • html_integration adds a test that exclude selectors apply to list items and table parts.
  • cargo test --workspace --all-features and clippy pass locally.

Risk

  • Low to medium.
  • Pages that hide content with inline styles or aria-hidden now produce less output. That is the intent, and callers who need it back can use include_hidden_content(true).
  • Exclude selectors now remove matching list items and table cells as well.

Checklist

  • Tests added or updated
  • Backward compatibility considered (CHANGELOG Unreleased entry)

Generated by Claude Code

Text a reader never sees is a prompt-injection vector for LLM consumers
(new threat T7).

- HTML: skip elements with hidden, aria-hidden="true", or inline
  display:none / visibility:hidden|collapse / opacity:0 / font-size:0,
  and <template>
- DOCX: skip w:vanish runs with a hidden_content_skipped warning
- include_hidden_content(true) opts back in
- Exclude selectors (and the hidden check) now apply to list items and
  table rows/cells, which previously bypassed them
@chaliy
chaliy force-pushed the claude/project-thread-ulbh3z branch from 9858296 to 3b52b41 Compare October 27, 2026 02:30
@chaliy
chaliy merged commit 9480d25 into main Oct 27, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant