Repository navigation
feat(security): skip hidden content by default - #42
Merged
Merged
Conversation
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
force-pushed
the
claude/project-thread-ulbh3z
branch
from
October 27, 2026 02:30
9858296 to
3b52b41
Compare
2 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Михайло · project thread
What changed
Content a reader never sees is no longer rendered by default.
HTML elements are skipped when they have:
hiddenattribute (but notuntil-found);aria-hidden="true";display:none,visibility:hidden|collapse,opacity:0orfont-size:0.<template>is stripped too.DOCX: hidden text runs (
w:vanish) are skipped. Ahidden_content_skippedwarning 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-onlyor 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.htmlbefore:After:
Tests:
tests/hidden_content.rscovers each HTML signal, DOCXw:vanish, the opt-in, theuntil-foundexception and the warning.html_integrationadds a test that exclude selectors apply to list items and table parts.cargo test --workspace --all-featuresand clippy pass locally.Risk
aria-hiddennow produce less output. That is the intent, and callers who need it back can useinclude_hidden_content(true).Checklist
Generated by Claude Code