Security and data handling
Where data goes, what is kept, and what has and has not been verified.
Evidence key. confirmed on a test site seen working on a test site. automated tests covered by automated tests only. in testing still being tested. No independent audit, penetration test or bug bounty exists yet.
Data flow
- A platform event (an issue update or a comment; a new attachment triggers an issue update about 2 seconds later) starts a trigger function. It lists the issue's attachments and queues
{issue key, attachment id}. confirmed on a test site - A queue worker downloads the attachment through the platform REST API, as the app, into function memory. confirmed on a test site
- The sanitizer runs in memory. automated tests
- With dry-run on (the default) nothing is changed and an audit row is written. automated tests
- With dry-run off and findings present, the app uploads
sanitized_<name>, edits comments and the description, re-reads to verify, writes the audit row, then deletes the original. confirmed on a test site - File content and matched values are never written to storage or logs. Only counts, rule ids and ids are. automated tests
No external network calls
Declared design
- The manifest declares no external fetch backends, and a test fails if one is added. automated tests
- There are no remotes and no custom UI. The admin UI uses the platform's own UI kit. automated tests
- The app source has no analytics, telemetry or CDN calls. The log module is the only output channel and allows only named fields. automated tests
- Third-party libraries that Forge bundles for the UI are listed in the project's dependency audit. automated tests
Not yet verified
The admin page's network requests have not been inspected in a browser, so the claim above rests on the manifest and the source, not on a traffic check. in testing
What is stored, where, for how long
| Data | Where | Content | Retention |
|---|---|---|---|
| Audit log | Forge SQL, table audit_log | Time, issue key, attachment id, file name (or its SHA-256 prefix if hashing is on), file type, status, redaction count, rule ids with counts, swap state, error code. No values. automated tests | Default 12 months, configurable 1 to 120. A daily job deletes older rows. automated tests |
| Settings | Forge key-value storage | Dry-run, size limit, extensions, email mode, allowlists, cookie-name allowlist, retention. automated tests | Until changed or uninstall |
| HMAC secret | Forge key-value storage (secret) | One random value per install, the key for redaction labels. automated tests | Until uninstall |
| Locks and swap progress | Forge key-value storage with expiry | Ids and phase names. automated tests | Locks 15 minutes, swap state 3 days |
| Leak audit and backlog progress | Forge key-value storage | Counters, issue keys, attachment ids, up to 200 failure records with error codes. automated tests | Replaced by the next run. Cancel flags 7 days. |
| Logs | Forge logs | Issue key, attachment id, counts, rule ids, status, error codes. automated tests | Per platform |
Attachment bytes and file contents exist only in function memory during one job. automated tests The vendor has no server and no copy of this data.
Redaction label design
- Format:
[REDACTED_BY_SECRET_SCRUBBER_<4 hex>]. The hex is the first 16 bits of HMAC-SHA256 of the matched value, keyed with the per-install secret. automated tests - Equal values give equal labels within one install. Different installs give different labels. automated tests
- With 16 bits, unrelated values can collide. A label is a marker, not an identifier. automated tests
- A plain hash was rejected because low-entropy secrets could be brute-forced from it. automated tests
Exposure window
The original is visible until the swap finishes
The original file is uploaded before the app can sanitize it. Until the swap completes, search or other indexing can see it. The app shortens this window. It cannot remove it. confirmed on a test site
Typically seconds; longer for large files or a slow site. No maximum is promised. Two different measurements exist, on a development site:
- Whole swap, small files: 5.6 to 6.7 seconds (mean about 6.0 seconds; 5 uploads of a small
.log), from the attachment's creation to the audit row. The audit row is written just before the original is deleted. confirmed on a test site - Start delay, earlier measurement: about 26 seconds from upload to the first job on a cold start, and about 11 seconds when warm. This measures when processing starts, not when the swap ends. confirmed on a test site
Not measured: large files, and the time until search can find the original.
Failure behavior
Deletion is permanent
Deleted originals cannot be restored. There is no undo. confirmed on a test site
- Deleting requires a verified-swap proof object in the type system. Code without a proof does not compile against the delete function. automated tests
- Any failure before the delete leaves the original untouched. The job retries with backoff. Terminal failures are audited as failed and shown in the issue panel. automated tests
- If the audit store is unavailable, the original is kept. automated tests
- Dry-run is on after install. It is the control that stops all changes. automated tests
Licensing
- With an inactive license nothing is processed. On a test install, five uploads started no processing, wrote no audit row and left the files untouched, because the platform's trigger filter stopped all work. With an active license, files were processed normally. confirmed on a test site
- The inactive banner, the trial state and the license log states are covered by automated tests only. They could not be shown on a development install. automated tests
- When the license is inactive, the read-only Leak audit stays available. automated tests
Scopes
The app requests three scopes. Each is the minimum for the function listed. automated tests
| Scope | Why | Evidence |
|---|---|---|
read:jira-work | Read attachments and their content, descriptions and comments. Search issues for the Leak audit. List attachments for the permission check. Receive events. | Download and description reads worked on a test site. confirmed on a test site |
write:jira-work | Upload the sanitized attachment. Edit comments and descriptions to repoint media. Delete the original. | A full swap worked on a test site with only these scopes plus project permissions. confirmed on a test site |
storage:app | Key-value storage for settings, the HMAC secret, locks, swap progress, scan and backlog progress. | Settings and locks worked on a test site. confirmed on a test site |
Not requested: no manage:jira-configuration, no admin or impersonation scopes, no external fetch permission. Forge SQL is declared as a module and needs no scope. Licensing needs no scope. automated tests
Scopes are added only when a feature needs them. Each future scope change has to be justified in the project's decision log first.
Project permissions
The app acts as itself, the app user. In every project it should handle, the documentation lists these project permissions (not scopes):
- Browse projects
- Create attachments
- Delete all attachments
- Edit all comments
In a service project the app user must also be able to see and edit internal comments. An internal comment was swapped and edited by the app on a test site, and it stayed internal. confirmed on a test site
A missing permission has not been reproduced
On the test site, removing one grant from "Delete all attachments" did not stop the app, and the Permission check still reported nothing missing. So a missing-permission failure has not been reproduced. Do not rely on removing a permission to stop the app. Dry-run is the control that stops all changes. confirmed on a test site
The admin page has a read-only Permission check. It ran on the test project and reported nothing missing. confirmed on a test site The Permission check listing a permission that is really missing has not been seen. in testing
Dependencies
A dependency audit on 2026-11-07 found 15 advisories (8 high, 7 moderate). All are inside Atlassian Forge packages and their children. The app does not import the affected packages directly. The finding is disclosed in the project's dependency audit. Whether the Marketplace review accepts it is not confirmed. automated tests
Not yet in place
None of these exist yet
No security certification, no compliance claim, no independent audit report and no penetration test exists yet. There is no bug bounty.
To report a vulnerability, write to security@secretscrubber.com. See the vulnerability disclosure policy.