Share links
How a Pentr share link works, what it grants, and how it is revoked.
A Pentr share link gives you read access to the sealed evidence of one penetration test run, without an account and without signing in. This page describes what the link grants, how long it lasts, and the ways it can stop working.
The shape of a link¶
A link looks like this:
https://<pentr-host>/share#8Jc2k…
The part after the # is the credential. It is a random token, 32 bytes of
entropy rendered in a URL-safe alphabet, and it is the entire credential: no
account, password or other identity is involved, and anyone holding it has the
access. Treat the URL the way you would treat a password.
Both halves have to survive the journey. A message that wraps or truncates the
URL after the # leaves you with a page that loads and then reports the link as
incomplete. Ask the sender to resend it in a form that keeps it intact.
What the token is, on the server¶
The plaintext token is returned once, to the person who created the link, and is never written down. What the database stores is the SHA-256 of the token.
SHA-256 rather than a password hash such as bcrypt, for two reasons given in the code. Bcrypt's cost factor exists to slow down guessing attacks against low-entropy human passwords; a 256-bit random token has enough entropy that no attacker is going to guess it, so the slowdown buys nothing. And a plain digest can be indexed, so presenting a token looks up exactly one row, where a bcrypt comparison would mean walking the table.
For you this has one practical consequence. Nobody can recover your link from the system — not support, not the person who sent it. A lost link is replaced, not retrieved.
What the token does not reveal to the server logs¶
The token sits in the URL fragment, the part after the #. Browsers do not
transmit the fragment when they request a page, so the token does not appear in
the request line of the server's access log, and it is not passed on in
Referer headers to anywhere you click through to.
It does still reach the server. The share page sends it as an
X-Pentr-Share-Token request header on the two calls it makes — one for the
manifest, one for the zip — so any intermediary configured to log request
headers would see it. The fragment placement keeps the token out of the ordinary
URL trail, not out of the request.
Those two calls are made with credentials omitted, so a browser that happens to
be signed in to Pentr does not attach its session cookie, and both responses are
marked Cache-Control: no-store so no shared cache holds a copy of an evidence
manifest after the link is withdrawn.
What the page shows you¶
Most of what the share page renders is read out of the stored manifest and the stored signature block rather than out of any mutable record: the framework the run was mapped to, a digest of the declared scope, the start and end times, the signature time, the chain algorithm and signature algorithm, the signing key identifier, the chain head, the artifact count, and one row per artifact with its sequence, kind, phase, size, filename, hash and entry hash.
Five values on the page are not from signed bytes. Three of them describe the run: the run identifier, the seal time, and the manifest hash, all read from the platform's own record of it — the manifest hash because it names which stored blob to read, so sourcing it from inside that blob would be circular. The other two describe the link rather than the run: the recipient label and the expiry date, both set by whoever created the link and stored on the link's own row. Treat all five as the platform's assertion rather than as something the signature covers.
The run identifier, at least, is checkable. The manifest inside the downloaded
zip carries it under signature, and pentr-verify prints the value it reads from
there, so the two can be compared.
Two things are deliberately absent. The findings themselves are not on this surface — artifact rows reference finding identifiers as bare UUIDs and nothing more — and the public key is not served here either, because a key that arrived with the evidence proves nothing about who signed it.
The server does not verify the locker for you. No re-hashing happens on the server side when this page is built, by design: a verdict the server hands you would be a verdict you have to take on trust. The page shows you values; the checking is yours to do, with pentr-verify.
Downloading the locker¶
The page offers the sealed run as a zip named pentr-locker-<run-id>.zip. That
zip is a complete evidence locker, and it is what you verify offline.
Download it. Do not plan to come back to the link.
Labels, expiry and revocation¶
Every link carries an expiry, and a link that has passed it stops resolving. The default is 30 days from creation and the sender can choose anything from 1 to 365 days. There is no option for a link that never expires.
A link can also be revoked at any moment, by whoever holds the Pentr account. Revocation takes effect immediately and needs no notice.
Revocation is not retroactive, and that asymmetry is the practical point of an offline locker: a zip you have already downloaded keeps verifying for as long as you keep it, whatever happens to the link it came through. Revoking closes future access, not copies already made.
Each link also carries a free-text label naming its recipient, so the sender can revoke one recipient's link without disturbing another's, and a counter of how many times it has resolved along with the time it was last used. A link is not bound to one viewer; the counter is how the sender notices one being passed around.
When a link stops working¶
| What you see | What it means |
|---|---|
| The evidence loads | The link is live. |
| "This share link has expired or been revoked. Ask whoever sent it for a new one." | The token is real, and the link behind it is no longer active. |
| "This share link was not found. Check that the whole link was copied, including everything after the # character." | No link carries this token. Usually a truncated or mistyped URL. |
| "Too many requests from this address. Try again in a minute." | A rate limit. |
Three rate limits apply to the public surface: sixty requests a minute from one address, ten failed token resolutions a minute from one address, and ten zip builds an hour per token. Only failures count against the tighter bucket, so reloading a page that works does not lock you out. The limiter fails open — if its backing store is unreachable, requests are allowed through rather than refused.
If you need the evidence to last¶
A share link is a delivery mechanism with an expiry date and an off switch held by someone else. If the evidence matters to a piece of work with its own retention requirements, take a copy while the link is live:
- Download the zip.
- Obtain the organization's public key through a channel you trust, separately from the link.
- Run
pentr-verifywith--keyand keep the output alongside the zip.
After that the archive stands on its own, and the questions it does and does not answer are set out in what verification does not prove.
Fetching without a browser¶
The share page is a convenience over two HTTP endpoints, and the token is a
header, so the same content is reachable from a shell. Substitute the part of
your link after the #:
curl -H "X-Pentr-Share-Token: <token>" "https://<pentr-host>/api/share"
curl -H "X-Pentr-Share-Token: <token>" \
-o pentr-locker.zip "https://<pentr-host>/api/share/locker"
A missing token answers 404, an expired or revoked one 410, and a throttled
request 429 with a Retry-After header.
Last updated 2026-09-24