/** * @param {string} styleStr * @returns {boolean} */ export function isHiddenStyle(styleStr: string): boolean; /** * True for an element a rendered page would not show: `hidden` attribute or a * hiding inline style. Works on both hast nodes and parseHtmlTag results. * @param {any} node * @returns {boolean} */ export function isHiddenElement(node: any): boolean; /** * @param {string} htmlValue * @returns {string | null} */ export function isHiddenOpen(htmlValue: string): string | null; /** * @param {string} htmlValue * @returns {string | null} */ export function closingTagName(htmlValue: string): string | null; /** * The keyed, content-addressed placeholder for one Layer-2 splice: * `[hidden HTML removed #]` / `[HTML comment removed #]`, where * `` is the first 12 lowercase-hex chars of sha256 over the UTF-8 * encoding of the ORIGINAL spliced text. Content-addressed on purpose: * identical spliced content yields the identical placeholder, so a rehydrator * can match placeholder → original by key alone, and duplicated content never * produces conflicting keys. * @param {SpliceKind} kind * @param {string} original the exact text the splice removed * @returns {string} */ export function layer2Placeholder(kind: SpliceKind, original: string): string; /** * Replace each range of `text` with its kind's keyed placeholder, preserving * every byte outside the ranges verbatim. Overlapping/nested ranges are merged * (defense-in-depth — the scanners emit disjoint ranges). * * Returns the spliced text plus `pairs`, one per emitted placeholder in output * order, each pairing the placeholder with the ORIGINAL bytes it replaced and * its start offset in the RETURNED text (UTF-16 code-unit string indices, the * same space as `ranges`) — everything a rehydrator needs to undo the splice. * @param {string} text * @param {SpliceRange[]} ranges * @returns {{ text: string, pairs: SplicePair[] }} */ export function spliceRanges(text: string, ranges: SpliceRange[]): { text: string; pairs: SplicePair[]; }; /** * Scan raw HTML for hidden content to strip and preserved tags to report. * Returned ranges are offsets into `html`; comments and hidden elements span * the whole element including its content (hast positions cover open tag * through matching close, and parse5 extends an unclosed element to the end * of the fragment — fail-closed for truncated markup). * @param {string} html * @returns {{ ranges: SpliceRange[], warned: ReturnType }} */ export function scanHtmlFragment(html: string): { ranges: SpliceRange[]; warned: ReturnType; }; /** * True when `text` is HTML source rather than markdown that merely contains * tags — see `htmlSourceTree` for the definition and the fail-open rationale. * @param {string} text * @returns {boolean} */ export function looksLikeHtmlSource(text: string): boolean; /** * Layer 2 over web-ingress text: splice out HTML comments and hidden elements * (keyed placeholders mark the cuts; all other bytes are preserved verbatim) * and count preserved scripting/resource tags for the caller's warning. Returns * null when there is nothing to strip and nothing to report. * * `splices` pairs every emitted placeholder with the original bytes it * replaced (see {@link spliceRanges}), so a caller can rehydrate the text — * nothing is lost, only hidden behind an identity-carrying placeholder. * * `unparseable` is set (true) only on the fail-closed path below, where the * whole input was withheld behind {@link UNPARSEABLE_PLACEHOLDER} rather than * spliced — the caller's warning must describe a whole-output withhold, not a * splice. There `splices` is `[]`: the parser blew up before any span could be * located, so nothing is recoverable per-splice (the caller's pre-splice * `reveal` is the only copy). * * Idempotent over its own output, and by CONSTRUCTION rather than by argument: * the scan is re-run over the spliced text until it finds nothing more, so the * returned text is a fixed point. One pass is not enough on its own, because * removing an element changes how parse5 reparents the bytes around it, which * can flip {@link htmlSourceTree}'s markdown/source verdict for the next run. * A document that has not settled within {@link MAX_SPLICE_ROUNDS} rounds is * withheld whole, on the same fail-closed path a parser blow-up takes. * @param {string} text * @returns {{ text: string, removed: { comments: number, hidden: number }, warned: { tags: Record, dataSrc: number }, splices: SplicePair[], unparseable?: true } | null} */ export function sanitizeHtml(text: string): { text: string; removed: { comments: number; hidden: number; }; warned: { tags: Record; dataSrc: number; }; splices: SplicePair[]; unparseable?: true; } | null; /** * `flagDigestValues` drops the digest exemption: an exact-digest-length hex * value under a generic parameter name is reported as payload rather than read * as a fingerprint. Off by default because the exemption is what keeps a * cache-buster, an ETag and a commit id quiet; on for a caller whose cost of a * missed 16-to-64-byte channel beats its cost of those false positives. Like * every option this module takes, it can only ADD detection. * @param {string} url * @param {{ flagDigestValues?: boolean }} [options] * @returns {string | null} */ export function checkExfilUrl(url: string, options?: { flagDigestValues?: boolean; }): string | null; /** * Host of a flagged URL — enough for the warning to name the destination * without echoing the payload-bearing query/fragment. * @param {string} url * @returns {string} */ export function urlHost(url: string): string; /** * Layer 3: report data-exfil-shaped URLs in markdown links/images/definitions * and HTML attributes (src/href/background/srcset/ping, form action/formaction, * meta-refresh). Detection only — the text is never modified; the caller * surfaces the threats as a warning. * * `autoFetched` marks a threat that needs no deliberate act to fire — a * rendered image, a stylesheet, a form target, a meta refresh — as opposed to a * link somebody has to follow. Both are reported; the caller uses it to decide * how loudly (see the exfil tier in ./output.mjs). * @param {string} text * @param {{ flagDigestValues?: boolean }} [options] see {@link checkExfilUrl} * @returns {Array<{ isImage: boolean, autoFetched: boolean, reason: string, target: string }> | null} */ export function detectExfil(text: string, options?: { flagDigestValues?: boolean; }): Array<{ isImage: boolean; autoFetched: boolean; reason: string; target: string; }> | null; /** * Layer 3, second detector: report URLs whose HOST is a confusable of an ASCII * name (`аpple.com`). Detection only, and deliberately independent of the * exfil-shape test above — a homoglyph domain needs no suspicious query to be * the whole attack, so `https://аpple.com/docs` is reported while * {@link detectExfil} stays silent on it. * * Fails CLOSED on a parse blow-up for the same reason detectExfil does. * @param {string} text * @returns {Array<{ severity: string, description: string }> | null} */ export function detectConfusableHosts(text: string): Array<{ severity: string; description: string; }> | null; export const REPORTED_TAGS: Set; /** * The single grammar definition for keyed Layer-2 placeholders — the exact * output of {@link layer2Placeholder}, capture group 1 = the key. Global so * callers can scan a document for every placeholder; reset `lastIndex` (or * use `matchAll`) between uses. */ export const LAYER2_PLACEHOLDER_RE: RegExp; export const HIDDEN_PLACEHOLDER: "[hidden HTML removed"; export const COMMENT_PLACEHOLDER: "[HTML comment removed"; export const UNPARSEABLE_PLACEHOLDER: "[HTML unparseable \u2014 withheld]"; export const DATA_URI_LENGTH_THRESHOLD: 4096; export type CollectedUrl = { url: string; isImage: boolean; autoFetched: boolean; context: "resource" | "form" | "refresh"; }; export type SpliceKind = "comment" | "hidden"; export type SpliceRange = { start: number; end: number; kind: SpliceKind; }; /** * One splice: the keyed placeholder now in the output text, the ORIGINAL * bytes it replaced, and the placeholder's start offset in the RETURNED text. * All offsets in this module — unist positions and these — are plain JS * string indices, i.e. UTF-16 code units. */ export type SplicePair = { placeholder: string; original: string; start: number; }; /** @returns {{ tags: Record, dataSrc: number }} */ declare function newWarned(): { tags: Record; dataSrc: number; }; import { HTML_TAG_PRESENT } from "./gates.mjs"; import { MD_LINK_HINT } from "./gates.mjs"; import { SECRET_HINT } from "./gates.mjs"; import { SECRET_HINT_EXT } from "./gates.mjs"; import { matchesSecretHint } from "./gates.mjs"; export { HTML_TAG_PRESENT, MD_LINK_HINT, SECRET_HINT, SECRET_HINT_EXT, matchesSecretHint };