hersona is a small, low-dependency PyPI library (YAML attribute templates +
a CLI). This document is deliberately modest in scope — it describes what
protections actually exist, not aspirational ones. Written in response to
an external review that (correctly) noted the project had no documented
threat model; see
docs/reviews/2026-07-04-external-review-response.md.
In scope:
- A malformed or oversized
hersona updatedownload corrupting the local data cache.hersona.core.updatecaps the downloaded archive at 64 MB, rejects path-traversal / non-regular archive members, and installs atomically (backup-then-swap; a failed install rolls back rather than leaving a half-written cache). - Transit-level tampering or corruption of a
hersona updatedownload (a compromised network path, a bad CDN edge, a truncated transfer). Since v1.7.x,hersona updatefetches a SHA-256 manifest (checksums.json, generated byscripts/gen_checksums.py) from a second, independent GitHub delivery path (raw.githubusercontent.com, distinct from thecodeload.github.comarchive endpoint) at the sameref, and verifies every extracted file against it before installing. A mismatch aborts the update with no partial install. Skippable with--no-verify; if the manifest simply isn't available for a givenref(e.g. an old tag predating this feature), verification is skipped with a warning (fail-open) rather than blocking the update. - Untrusted attribute YAML content. Attributes are data (YAML validated
against
schema/attribute.schema.json), not executable code — loading one does not run arbitrary Python.scripts/validate.pyand CI schema validation catch structurally invalid files before merge.
Out of scope (please don't rely on this document for these):
- A compromised
shiro-0x/hersonaGitHub account or repository. The archive and its checksum manifest both originate from the same commit tree; an attacker who can rewrite the repository (or push malicious commits with valid credentials) can rewrite both consistently. This is not code signing, not Sigstore/SLSA build provenance, and does not protect against a supply-chain compromise at the source. It only detects tampering/corruption introduced after GitHub served the content — i.e., in transit or at a compromised intermediate cache/CDN edge, not a compromise of GitHub or the account itself. - A malicious PyPI release.
hersona's PyPI publish workflow uses Trusted Publishing (OIDC, no long-lived API token in CI) — this removes the risk of a leaked PyPI token being used to publish a rogue release, but it does not itself attest that the published artifact matches a specific source commit. Build provenance attestation (actions/attest-build-provenance) is planned to close that gap; check.github/workflows/publish.ymlfor current status. - Prompt injection via attribute content at inference time. Attribute YAMLs are authored to be injected into an LLM system prompt. hersona does not sandbox or filter what an LLM does with that content at response time — that's the responsibility of whatever agent framework or application embeds hersona.
- Model behavior, hallucination, or persona-driven misuse. See
DISCLAIMER.md.
Please open a GitHub issue for non-sensitive reports. For anything you'd rather not disclose publicly before a fix is available, use GitHub's private vulnerability reporting (repository Security tab → Report a vulnerability) if enabled, or reach the maintainer through the contact listed on their GitHub profile. There is no dedicated security email or bug bounty at this time — this is an individually maintained open-source project.
hersona update --ref v1.7.0 # pin to a tag rather than a moving branchPinning --ref to a tag (rather than the default main branch) avoids a
theoretical race where the archive and checksums.json are fetched a
moment apart while the branch is being pushed to. Tags are immutable, so
both requests resolve to the same content regardless of timing.
To inspect the manifest yourself: it's a plain JSON file at
checksums.json in this repository, one SHA-256 hash
per file under attributes/ and schema/. Regenerate and diff it with
python scripts/gen_checksums.py --check.