Documentation Index
Fetch the complete documentation index at: https://docs.tryhoard.com/llms.txt
Use this file to discover all available pages before exploring further.
Security
Hoard’s sync agent runs on your machine and drives a real browser session against your TCGplayer seller account. That’s a lot of trust, so we treat the integrity of what runs on your machine as a first-class engineering problem, not a marketing line. This page explains exactly what we do, why, and — for the security-minded — how to verify our claims yourself without taking our word for any of it.TL;DR for sellers
- Every binary you download is cryptographically signed by us. Your agent refuses to install or run a tampered binary.
- The browser-automation script the agent runs (selectors, URLs, click steps) is also signed. The same protection applies to the instructions, not just the program.
- Older versions can’t be replayed. If an attacker somehow got their hands on a copy of our distribution server, they can’t trick your agent into rolling back to a known-bad version.
- You can verify every claim above using only public tools —
curl,openssl, and our open verification code. We show you how below.
What’s signed and how
Hoard ships two kinds of cryptographically signed artifacts:| Artifact | Path / URL | Signing method |
|---|---|---|
| Agent binary | releases.tryhoard.com/hoard-agent_<os>_<arch>_v<version> | ed25519 over file bytes |
| Workflow YAML bundle | releases.tryhoard.com/workflows/tcgplayer/current.json | ed25519 over a domain-separated payload (see below) |
Why two artifacts when they share a key
The agent binary is the program. The workflow YAML is the script that program runs (which buttons to click, what URL parameters mean, how to recognize “logged in”). TCGplayer ships UI changes more often than we ship agent releases, so we want a path to push selector fixes faster than a binary release cycle. Same trust boundary, different update cadence. To prevent a binary signature from ever being mistakenly accepted as a workflow signature (or vice versa), the workflow signed payload is prefixed with a fixed domain separator string:TestVerify_RejectsCrossProtocolSignature in agent/internal/workflowfetch/fetcher_test.go).
Anti-rollback
Both signed artifacts include a monotonic version. For the agent binary it’s the release tag (v0.8.18 etc.). For the workflow YAML it’s the unix timestamp of the last commit to the canonical YAML on main, computed by CI as git log -1 --format=%ct -- agent/workflows/tcgplayer.yaml. Monotonic by construction, no human bumping, no off-by-one.
The agent persists the highest version it has ever successfully verified to its config directory and refuses to load anything older, even if the signature is valid. So an attacker who compromised our CDN couldn’t replay an older bundle that contained a known-bad selector to redirect your purchases somewhere else. The version pin moves forward only; it never resets.
How to verify our claims yourself
This is the part most companies skip. Everything below works with publicly available tools — no Hoard account needed.1. Pull the live signed bundle
2. Reconstruct the signed payload
The signed bytes areheader || yaml_bytes, where header is the literal text:
\n).
3. Verify the signature
The verification logic the agent runs is open in our repo atagent/internal/workflowfetch/fetcher.go. It’s about 200 lines of Go, no external crypto libraries, just crypto/ed25519 from the standard library.
If you have Go installed, the simplest end-to-end check is to clone our repo and run our test suite:
Threat model
What an attacker cannot do without the private signing key (which lives only in GitHub Actions secrets):- Push a malicious agent binary that your agent will install and run.
- Push a malicious workflow YAML that redirects clicks to a different domain or scrapes additional fields.
- Roll your agent back to a previously-known-vulnerable selector to re-enable an exploit we’ve already fixed.
- Replay a binary signature as a workflow signature (the
hoard-workflow-v1domain separator blocks this even though both artifacts share a key). - Tamper with a bundle in transit. TLS already protects this, but signature verification provides a second independent layer; the agent rejects the bundle even if TLS is somehow bypassed.
- Compromise of the GitHub Actions signing secret would let them push either malicious binaries or malicious workflows. This is the same risk surface as any signed-release ecosystem (Linux distros, Apple notarization, etc.). Mitigations: secret access is restricted to release workflows by GitHub branch protection, and the signing private key never touches developer workstations or local CI runners. Signed-release detection is on the binary update path: the agent verifies the signature of every binary it downloads and restores from backup if verification fails.
- Refuse to serve updates entirely (DDoS our CDN). Your agent keeps running the last-good cached workflow indefinitely; an attacker who can take our distribution offline cannot use that to push you a bad version, only delay good ones.
- Show you a stale-but-still-valid bundle (replay attack on the network layer). The version pin blocks this — your agent has already accepted version N, and a replay of version N or an older signed version is rejected on receipt.
Source you can inspect
These are the files that implement everything described above. You’re welcome to read them and tell us what’s wrong.agent/internal/workflowfetch/fetcher.go— fetch + verify + cache, ~250 lines.agent/internal/workflowfetch/fetcher_test.go— 14 tests pinning every security property.agent/internal/update/signing_key.go— embedded public key.agent/internal/update/updater.go— binary signature verification on self-update..github/workflows/agent-release.yml— agent binary release pipeline (signing step, R2 upload)..github/workflows/workflow-yaml-release.yml— workflow YAML release pipeline (signing step, self-verify-before-upload, R2 upload).
Reporting a security issue
If you find a vulnerability, please email security@tryhoard.com. We commit to:- Acknowledging receipt within one business day.
- Assigning a tracking ID and a single point of contact.
- Treating coordinated disclosure as the default — we’ll work with you on a public-release timeline that gives users time to update.