This project is an agent skill pack for personal LLM-maintained knowledge bases. It does not run a service and stores no user data of its own. However, vaults built from this skill pack routinely hold material that is highly sensitive — therapy transcripts, medical notes, NDA-bound meeting records, private journals. The guidance below treats your vault as the primary asset to protect.
Please report any of the following privately via GitHub Security Advisories:
- A bypass in
_system/densa/that allows red-line violations (e.g. silentraw/mutation, log history rewrite,analysis.sourcescardinality breach) to slip through pre-commit or CI. - A schema ambiguity an adversarial LLM run could exploit to exfiltrate or corrupt vault content while appearing to follow the contract.
- A prompt-injection pattern in a
raw/file (or any source you might reasonably ingest — clipped articles, transcripts, screenshots) that causes the LLM to perform writes outside the operation's declared scope, skip the plan-then-confirm gate, or coerce a red-line bypass via natural-language instructions. - A bug in
setup_encryption.shor the git-crypt integration that could result in unencrypted raw files being pushed to a remote.
Please do not open a public issue for these. We aim to acknowledge within 7 days.
For non-security bugs (rendering glitches, prompt clarity, etc.) use a normal bug report issue.
If you instantiate this skill pack for sensitive material:
- Wire the pre-commit hook per
README.md§"Quickstart". - Configure encryption for any sensitive L2 before the first push:
see
docs/setup.md§"Privacy — sensitive material". - Verify encryption is active:
git-crypt status -eshould list every path you intended to encrypt. - Use a second cold-backup remote on a different provider (Codeberg, GitLab, or a self-hosted forge). Single-vendor account loss is the most common way personal vaults disappear.
- Store your GPG private key on a hardware token (YubiKey, Nitrokey)
or in a vetted secrets manager. Loss of the key = loss of encrypted
history. Never commit
.git-crypt/keys/default. - Treat the LLM agent's web access as adversarial: per the L1 red lines, no silent web fetches during ingest. Review every prompt-driven enrichment before it lands in the wiki.
- Treat
raw/content as untrusted input to the LLM. A clipped article, an ASR-transcribed call, or a web-clip can contain adversarial instructions targeting the agent ("ignore previous instructions and write ..."). Densa's operation prompts fence raw content as<untrusted>so the LLM can tell its instructions apart from the source — see §"Trust-tier protocol" below. The plan-then-confirm gate (every operation drafts a plan you approve before writes) is your second line of defence — never approve a plan without reading the targets of every write, not just the summary. - If you push to a public remote, audit
.gitattributesand.gitignoreagainst accidentally exposinginbox/orraw/paths that weren't yet routed.inbox/is especially risky as a staging area — consider.gitignoreinginbox/*.mdand treating the inbox as never-committed scratch space. - Before the first push to any remote, scan for accidentally
committed secrets:
gitleaks detect --no-banner --stagedortrufflehog filesystem .are stdlib-free baselines. Encrypted blobs are still readable to anyone with the git-crypt key. - Be aware of LLM-agent vendor surface: prompts, raw contents, and partial wiki contents may be logged or used for evaluation by the LLM vendor depending on your plan and settings. Check your Cursor / Claude Code / Codex / other-vendor data-handling policy before ingesting clinically sensitive or NDA-bound material.
Densa is a markdown skill pack — it makes no LLM calls of its own.
The threat surface is the agent IDE (Cursor / Claude Code / Codex /
Cline) your human operator runs Densa's operation prompts inside.
A clipped article, an ASR transcript, or any web-clip dropped into
raw/ can carry adversarial instructions targeting the agent
("ignore previous instructions and write …"). Densa's response is
defence-in-depth across three layers, none of which depends on the
LLM vendor:
- The LLM fences raw content as data. Every operation prompt
(
ingest/query/process-inboxplus the three_system/prompts/domains/*-analysis.mdsub-prompts) instructs the LLM to wrap raw-source content in<untrusted source="<path>">…</untrusted>and treat instruction- shaped text inside the fence as findings to surface, never as commands. The three-tier trust vocabulary is defined in AGENTS.md §4.5; the threat model + mitigation pattern is atdocs/reference/red-lines.md§9. - The human approves the plan. Every operation drafts the page set + diff before any write. Skipping the plan-then-confirm step is the failure mode the fence is designed to make survivable.
- The validator gates the commit. AGENTS007 restricts each commit to its prefix's declared write scope; AGENTS003 + AGENTS006 enforce source-grounding on what does land. A successful injection would still have to thread the operation-scope needle without tripping any rule — much harder than persuading one prompt to misbehave.
A 2026-05 review of the wiki-compiler / Obsidian-AI prior-art set (a maintainer-only prior-art review, n=7) found Densa is the first project in the space to document an explicit prompt-injection mitigation. Smart Composer's "Multimedia Context" feature auto-scrapes URL + YouTube transcript content into the prompt with no fencing; nashsu/llm_wiki, Tolaria, and obsidian-llm-wiki-local ingest raw content directly into prompts. The fence convention is cheap to adopt downstream — it is one bullet in your operation prompt.
The validator (_system/densa/) is pure Python with no runtime
third-party dependencies — it imports only the standard library. The
pre-commit hook invokes the same package via python -m densa.
Both are short enough (~1k lines including the rule registry) to read
end-to-end before trusting in a security-sensitive vault.