Skip to content

Security: shiro-0x/hersona

Security

SECURITY.md

Security

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.

Threat model — what this project protects against

In scope:

  • A malformed or oversized hersona update download corrupting the local data cache. hersona.core.update caps 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 update download (a compromised network path, a bad CDN edge, a truncated transfer). Since v1.7.x, hersona update fetches a SHA-256 manifest (checksums.json, generated by scripts/gen_checksums.py) from a second, independent GitHub delivery path (raw.githubusercontent.com, distinct from the codeload.github.com archive endpoint) at the same ref, 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 given ref (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.py and 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/hersona GitHub 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.yml for 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.

Reporting a vulnerability

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.

Verifying a hersona update download yourself

hersona update --ref v1.7.0   # pin to a tag rather than a moving branch

Pinning --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.

There aren't any published security advisories