For owners
Ask for your code to be checked
Immune reviews only code whose owner asked for it. Asking takes a few minutes, and none of it is secret: your consent, your terms and every coin are on the record on gno.land.
You will need a gno.land account in Adena (version 1.22.2 or later) or gnokey, a little GNOT for fees, and the age tool to read what volunteers send you.
1. Show that the code is yours
Pick the way that fits your code. In the lines below, g1youraddress stands for your gno.land address; connect Adena and it is filled in.
A file in your repository
For a git repository on codeberg.org, github.com, gitlab.com.
- Register it with the form below. You get a target id, such as
t7. - Commit a file named
.gnosh-immuneat the root of your default branch, holding this line with your target id:gno.land/r/g14ssyf3yvlq3usd2z03uzgmx65vl47y8d8rk7fg/immune t7 g1youraddress - That is your consent. Every volunteer's gnosh checks the file on the tip of your default branch, and that the revision under review is in that branch's history, before it claims a piece. Take the line out and new work stops.
Forks and mirrors are refused, and a commit that exists only in a pull request does not count.
One line in your domain's security.txt
No commit needed, if your project already says where to report security issues.
- Add one line to
https://example.com/.well-known/security.txt, naming the repositories it covers (with none listed, it covers any you register):Immune: gno.land/r/g14ssyf3yvlq3usd2z03uzgmx65vl47y8d8rk7fg/immune g1youraddress https://github.com/example/project - Your repository's
SECURITY.md(at its root, in.github/or indocs/) must name your domain, as the host of a link or of an email address. Most projects already have one:# Security Please report vulnerabilities to security@example.com. - Register it with the second form below: the domain, the repository, and the pin hash of your security.txt. That is the sha256 of its Contact, Encryption, Canonical, Policy, Preferred-Languages and Immune lines, each written
name: valuein lower case with single spaces, sorted, one per line. Expires and comments are left out, so renewing the file does not change it. Pick a saved copy of the file in the form and your browser works it out, or, for a file without a PGP signature:curl -sfL https://example.com/.well-known/security.txt | tr -d '\r' | awk 'NR == 1 { sub(/^\357\273\277/, "") } { i = index($0, ":"); if (!i) next n = tolower(substr($0, 1, i - 1)); gsub(/^[ \t]+|[ \t]+$/, "", n) if (n !~ /^(contact|encryption|canonical|policy|preferred-languages|immune)$/) next v = substr($0, i + 1); gsub(/[ \t\f\v]+/, " ", v); gsub(/^ | $/, "", v) print n ": " v }' | LC_ALL=C sort | awk 'NR > 1 { printf "\n" } { printf "%s", $0 }' | sha256sum
Why both sides. A domain is not a repository. Whoever controls example.com could otherwise sign up someone else's code and have its findings sealed to them. The SECURITY.md is the repository's own people pointing at your domain; look-alike hosts and bare mentions do not count.
The file must be valid by RFC 9116: served over HTTPS from the domain itself, with a Contact, an Expires in the future, and, if it has Canonical lines, one naming the address it is fetched from. A whole file, for example:
Contact: mailto:security@example.com
Expires: 2027-11-01T00:00:00Z
Canonical: https://example.com/.well-known/security.txt
Immune: gno.land/r/g14ssyf3yvlq3usd2z03uzgmx65vl47y8d8rk7fg/immune g1youraddress https://github.com/example/project
gno.security fetches it every minute and shows on your target's page whether it still names you and whether its contact and opt-in lines are still the ones you pinned. Renewing Expires changes nothing; when you change a contact, pin the file again there.
A Gno package on gno.land
Register it as kind gno with its path, such as gno.land/r/g1youraddress/app. Its namespace must be your address or a name registered to you; the realm checks that itself.
Proposed for you by an admin
If an admin attested your code for you after you agreed, it waits for you on its target page. Accept it there with your own key.
Register
2. Set your terms
On your target's page. They are what you promise volunteers, published before anyone starts:
- Seal key
- Your age public key. Reports are sealed to it, and only you can read them until you disclose. Make one and keep the private half safe:
age-keygen -o owner.key age-keygen -y owner.key # prints age1..., your seal key - Reviews per piece
- 1 to 3 volunteers check each piece, independently.
- Stipend
- Paid for every review you do not reject, holes or not. An honest "nothing found here" is work too.
- Bond
- What a volunteer puts up per claim. It comes back with an accepted review and goes to the commons with a rejected one, so junk costs its sender.
- Bounties
- What you pay for a hole by how bad it is: low, medium, high, critical, rising.
- Embargo
- 7 to 90 days after a round closes, for you to fix and disclose. Nothing is opened before.
- Record needed
- How many accepted reviews a volunteer needs before they may claim your code.
- Models
- You may ask volunteers to use models they run themselves, so no model provider sees your code's holes.
Setting terms is your signed agreement to the realm's safe harbor:
The owner authorizes good-faith security review of the registered code, at the revisions it lists in rounds, by volunteers following these terms: source review and local testing only, no access to any running system, findings sealed to the owner until the round is disclosed or its embargo ends. The owner will not pursue legal action against volunteers acting within these terms.
3. Fund it
Anyone may back your target, you too, from its page; a new backer gives at least 1 GNOT. You are just another backer: there is no way for backers' money to reach you. Each backer can take back their own unspent share whenever no round is open or waiting for its verdicts.
4. Open a round
On your target's page: name one revision (a full commit hash) and the tip of your default branch that holds your consent, and list the pieces to review, one path per line, up to 200, each with a hint for the volunteer if you like. Set a bounty reserve of at least one critical bounty. The round locks pieces × reviews × stipend, plus the reserve, from the pot.
5. Read, fix, disclose
- Reports arrive sealed to your key. Each report's page has its sealed text; read it with your owner key:
Each report holds its finding, a fix as a patch, a test that fails before the fix and passes after, and the report's own key (an AGE-SECRET-KEY line).age -d -i owner.key sealed.age | tail -c +5 | gunzip - Close the round when you have enough, or it closes after 30 days. Your embargo starts then.
- Before your deadline, disclose the round on its page: one line per report with its verdict, its severity and its key. Every report opens to everyone and the pot pays: accepted reports get the stipend, the bounty and the bond back; duplicates the stipend and the bond back; rejected ones nothing, with their key published so anyone can see what was rejected.
If you stay silent past your deadline, finders may open their own reports and are paid the stipend; thirty days later anyone may lapse the round, and the finders who opened share your bounty reserve. Your record shows rounds disclosed on time, late and never.