Skip to content

Security: pythonhk/github-native-event-starter-canary-20260805-0729

Security

SECURITY.md

Security policy

Reporting a vulnerability

Do not open a public issue, discussion, pull request, or event submission for an unfixed vulnerability, suspected credential exposure, private-key incident, or confidential participant-data exposure.

Use the Report a vulnerability button in this repository's Security tab to open a private vulnerability report. If private vulnerability reporting is not enabled in a generated event repository, contact the pythonhk organization owners through the private security contact published by that event. Organizers must render the exact route in this file and docs/participant/event-details.md, test it, and verify it is reachable before opening registration. “Contact organizers” without a working private destination is not sufficient.

Include only what is necessary:

  • affected event/repository URL and numeric repository ID if known;
  • protocol, template, and eventctl versions;
  • affected workflow, command, state revision, attempt, or receipt identifiers;
  • reproduction steps using synthetic data;
  • expected versus observed behavior and security impact;
  • relevant public commit/run/PR IDs and UTC timestamps;
  • whether active exploitation or secret/plaintext exposure is suspected.

Never send a GitHub token, App/decryption/signing private key, recovery phrase, real confidential submission, or another participant's private data. Redact workflow logs before attaching them.

Organizers should acknowledge a complete report within three business days, establish a private coordination channel, and prioritize containment over event availability. Do not promise a disclosure date until scope and remediation are understood.

Supported versions

Security fixes are supported for the current tagged template release and the exact eventctl versions pinned by active, non-archived event repositories. Generated repositories are independent copies: template fixes do not propagate automatically. Each event's organizers are responsible for reviewing, testing, and evidencing compatible code/control upgrades. Protocol v1 cannot adopt a new signed event configuration or authority in place; those changes require a new event instance.

Archived events retain verification documentation and receipts but do not accept new protocol operations.

Security model

Protected assets

  • participant signing keys and organizer/judge decryption keys;
  • GitHub App and Actions credentials;
  • confidential submission plaintext and hidden judge material;
  • registration, membership, quota, attempt, score, and leaderboard integrity;
  • availability of pause, close, recovery, and audit operations;
  • integrity and provenance of released eventctl binaries.

Trust assumptions

  • GitHub authenticates the source actor/object metadata supplied to a trusted base-repository workflow or API call.
  • Numeric GitHub IDs are stable protocol identity; login names are display data.
  • Organizers control reviewed code on the protected default branch.
  • The dedicated state-writer App retains its documented least privilege.
  • Cryptographic algorithms and dependencies are used through the reviewed Go CLI rather than reimplemented in Bash.
  • External judges meet the isolation properties documented in docs/scoring/external-judge.md.

Untrusted inputs

Treat all fork contents, branches, commit messages, PR/issue/comment text, usernames, filenames, archives, workflow artifacts from untrusted runs, scoring output, and network responses as hostile. A valid signature proves only the bound key/context; it does not make payload content safe to execute.

Required invariants

  • The authenticated numeric actor equals the signed actor and registered key.
  • Every team member independently consents to the identical complete manifest.
  • Participant code/content never executes with secrets or state write access.
  • A submission binds event, epoch, actor, team, attempt, repository, PR number and immutable database ID, fork repository, branch, head SHA, configuration, and content digests.
  • Exact replay is idempotent; changed content under an existing intent fails; fresh attempts are charged once according to policy.
  • State is append-only, deterministic, public-data-only, and updated by non-force compare-and-swap.
  • Scoring output carries no authority until independently validated and applied by the state reducer.
  • Every mutating worker reloads the emergency gate immediately before commit.
  • Released CLI assets are immutable, checksum-pinned, signed/attested, and natively tested.

GitHub Actions policy

Untrusted pull_request validation has read-only contents permission, no secrets, and no self-hosted runner. Privileged pull_request_target or workflow_run jobs must not check out, execute, import, cache, or trust participant-controlled content. They re-fetch bounded metadata and verify all numeric IDs and digests.

Third-party Actions are pinned to full commit SHAs. Workflow permissions are declared explicitly. State writing and PR reporting use separate tokens. Receipt signing uses a distinct Ed25519 key whose age-scrypt-encrypted private key and passphrase are environment secrets in the event-receipt-signer environment, whose custom deployment policy admits only the repository's exact default branch. It is not a repository secret and is never available to fork-triggered validation or feature-branch dispatches.

Data handling

Every public branch, issue, pull request, Actions log, artifact, comment, and receipt should be assumed public. The state branch contains public protocol metadata only. Confidential payloads are encrypted before Git publication and decrypted only in the approved isolated judge.

Encryption does not justify committing signing-key backups, excess personal data, or material without an event need. Organizers publish retention, disclosure, and deletion limitations before registration. Git history and public forks may make complete deletion impossible.

Incident response

The first response to suspected integrity, credential, judge, or confidentiality compromise is an out-of-band emergency pause, followed by evidence preservation and credential containment. Do not rewrite state history. See docs/recovery/incident-response.md.

Known limitations

  • Generated event repositories are independent copies. Security fixes and settings changes do not propagate automatically from the starter.
  • Public Git history and forks may retain ciphertext and public protocol data indefinitely. A later decryption-key compromise may expose retained ciphertext. Organizers must minimize collected data and use fresh recipients only in a brand-new event instance; protocol v1 cannot rotate the configured recipient set in place.
  • Encryption hides plaintext and filenames inside the bundle but does not hide its signed public routing fields (including actor/team/attempt identifiers), repository activity, commit/PR metadata, bundle size, or submission timing.
  • Protocol v1 caps the complete bundle at 48,000,000 bytes, configured ciphertext at 47,000,000 bytes, and total/per-file plaintext at 42,000,000 bytes. Git LFS is outside the accepted retrieval contract. Each attempt still persists its encrypted object in public Git history.
  • Each v1 submission recipient is a strict age hybrid ML-KEM-768+X25519 recipient (age1pq1...), identified in signed envelopes as age-hybrid-mlkem768-x25519 with stanza type mlkem768x25519. When more than one recipient is configured, any one can decrypt; this is not threshold encryption. Protect every recipient private key accordingly. The participant can authenticate the signed recipient identifiers but cannot prove the exact ciphertext stanza set without the private identities. The isolated judge must load all configured HybridIdentities and reject omitted, extra, duplicate, classic, plugin, or mixed-mode stanzas. The passphrase-encrypted local signing-key backup uses age scrypt and is a separate format and trust boundary.
  • Participant key generation, packaging, inspection, and verification are supported on the locked macOS, Linux, and Windows targets. Full submission decryption/extraction is judge-only in protocol v1: it runs in an ephemeral isolated Linux/private parent and fails closed on Windows until native owner-only ACL privacy is implemented and validated.
  • GitHub Actions delivery, scheduling, and concurrency are not exactly-once guarantees. Durable source/intent ledgers, compare-and-swap, and reconciliation provide idempotent state effects.
  • GitHub-hosted workflows are not a general sandbox for hostile participant code. Arbitrary execution requires the separately operated external judge.
  • Repository deactivate stops automation but cannot retract public forks, ciphertext, downloaded releases, or already published evidence.

Out of scope

The following are normally not vulnerabilities unless they bypass a documented security boundary:

  • public availability of fields explicitly listed in the event's public-data policy;
  • denial of service requiring unrealistic volume and causing no integrity or confidentiality impact;
  • results from a modified fork-local workflow that are never trusted upstream;
  • social-media impersonation without a defect in repository identity binding;
  • reports that require disclosure of another person's private key or data.

Do not perform disruptive testing against a live event, access other participants' data, exhaust quotas, or degrade GitHub/external-judge service. Use a disposable repository and synthetic accounts/data.

There aren't any published security advisories