1
0
Fork 0
llm-ingestion-pipeline-secu.../SECURITY.md
Kjell Tore Guttormsen e9d8fb2b9d docs(limits): two limits are conceded for 1.x, and the last 'pending' is retired
D3: :492 (Severity carries disposition intent) and :460 (the input-cap
asymmetry) are the two limits that can only be closed by changing an
exported symbol. Both now say 'conceded for 1.x', with the 2.0.0
consequence spelled out, instead of 'deferred deliberately'.

D5: :88's 'a calibration fix is pending' is gone. The concession is
narrower than the other two -- no fix is promised, but it is calibration,
so one may land in any 1.x release without breaking the contract.

SECURITY.md carries the part an outsider acts on: the support window is
rewritten off 'pre-1.0', the freeze is stated as a promise about the
Python surface and explicitly NOT about detection behaviour, and the two
permanent concessions join the documented-boundaries list.
2026-08-13 22:15:02 +02:00

83 lines
3.9 KiB
Markdown

# Security policy
`llm-ingestion-guard` is a defensive library for LLM ingestion pipelines. Its own
security posture matters: a flaw here can silently admit a poisoned artifact into a
downstream corpus. Reports are welcome.
## Supported versions
The project is `1.x`. Only the latest published version receives fixes; there are no
back-ported security branches. Pin a version and watch the `CHANGELOG.md`
`### Security` entries.
**What `1.0.0` freezes, and what it does not.** The freeze is a semver promise about
the *Python surface*: no name exported from `llm_ingestion_guard` is removed, renamed
or given a different meaning without a `2.0.0`. It is **not** a promise that detection
behaviour holds still. Severities, thresholds, lexicon entries and the dispositions
they produce are calibration, and calibration moves in minor and patch releases — a
payload that disposes `WARN` on `1.0.0` may dispose `FAIL_SECURE` on a later `1.x`,
and that is a fix rather than a break. Pin a version if you depend on a specific
grading, and assert on the disposition your policy requires rather than on a severity
you happened to observe.
## Reporting a vulnerability
**Do not open a public issue for a vulnerability.** Public disclosure before a fix
gives an attacker a window against every downstream consumer.
Instead, report it **privately** to the maintainer via the canonical repository on
Forgejo:
- Repository: `git.fromaitochitta.com/open/llm-ingestion-pipeline-security`
- Contact the maintainer directly through that Forgejo instance (private message /
maintainer contact) and mark the subject `SECURITY`.
Please include:
- affected version / commit,
- a minimal reproduction (input → observed disposition/finding vs. expected),
- the impact you see (e.g. a poisoned artifact that disposes `WARN` instead of
`FAIL_SECURE`).
Obfuscate any real payloads the same way the test corpus does — build attack strings
from `chr(0x…)` fragments so the report itself does not ship a live carrier.
## What counts as a vulnerability
In scope (a real finding):
- a bypass of a **stated** control — e.g. an invisible carrier that reaches the
persist gate without failing secure, a credential that egresses without a
`decoded:egress:*` / `egress:*` label, a `guard()` path that fails *open*;
- a `prepare_input` / `screen_output` code path that raises instead of failing
closed;
- a ReDoS or unbounded-resource input against the scanner.
Out of scope (documented boundaries — see the **Known limitations** section of
`README.md`, not vulnerabilities):
- semantic / factual poisoning invisible to lexicon + entropy;
- a HIGH finding in *trusted* prose disposing to `WARN` (§4.7 trust-scaling);
- hex-wrapped (non-base64) secret egress;
- multimodal / binary-layer carriers (OCR, font stego, VBA/macros, encrypted files);
- the multilingual homoglyph-mix false positive;
- a low `Severity` on an ordinary outward fetch — on the detection side 1.x does not
separate *what was seen* from *how bad it is*, so read the finding `id` for the
capability;
- the input-cap asymmetry at `MAX_INPUT_CHARS`: surfaces that return content raise
`OversizeInputError`, surfaces that return findings truncate and emit
`active:oversize-input`. Past the cap, "no finding" means "not looked at".
The last two are conceded for the whole of `1.x`, deliberately and in writing
(`docs/LIMITATIONS.md`): closing either changes an exported symbol's meaning and is
therefore a `2.0.0` change. The homoglyph false positive is conceded differently — no
fix is promised, but it is calibration, so one may land in any `1.x` release.
If you are unsure whether something is in scope, report it privately anyway.
## Disclosure
This is a small project without a formal embargo SLA. The maintainer will
acknowledge a report, agree a fix + disclosure timeline with the reporter, and
credit the reporter in the `CHANGELOG.md` `### Security` entry unless they prefer to
remain anonymous.