Secret Scanning and Secret Protection
A credential that is committed to a repository is exposed to everybody who can clone it, and to every backup of it. Gitea Enterprise v27.3.8 adds two layers of defense:
- Secret scanning reads the code (and optionally the history) of your repositories and reports committed secrets as findings on the repository Security page.
- Secret protection (push protection) reads a push before it lands and refuses it when it introduces a secret, so the credential never reaches the repository.
Secret scanning is part of the Security scan feature, next to dependency scanning and code scanning. All three share one Security tab, one settings page, one lifecycle (open, closed, dismissed) and one API.
Enable secret scanning
Section titled “Enable secret scanning”For the instance
Section titled “For the instance”Open Site Administration > Security. The Secrets section offers:
| Setting | Description |
|---|---|
| Allow secret scanning across this instance | Instance-wide permission to run secret scanners (default on). When it is off, saved repository preferences are kept and take effect again once it is turned on. |
| Enable Secret Scanning by Default | Repositories that never saved their own security scan settings follow this switch (default off, so an upgrade does not start reporting secrets in repositories nobody asked about). |
For a repository
Section titled “For a repository”- Open
Repository > Settings > Security Scan. - Enable security scanning and choose the Branch Patterns to scan, for example
main,release/*. Blank scans only the default branch. - In the Secrets section, choose the Scanner and set its options.
- Save. Saving triggers a rescan with the new configuration.
Organization and user owners can set defaults on their own settings page. New repositories copy them, and repositories that never saved their own settings follow them.
Scanners
Section titled “Scanners”| Scanner | Description |
|---|---|
| Built-in | Ships with a set of detectors for common credentials: AWS access key IDs and secret keys, GitHub and GitLab tokens, Slack tokens, Google API keys and service account keys, Stripe live keys, Azure storage keys, private keys, JSON web tokens, certificates, and a generic “name = value” rule that only fires on high-entropy values. You can turn single rules off and add custom rules. |
| Gitleaks ruleset | Applies the Gitleaks TOML ruleset ([[rules]], [rules.allowlist]) that the repository commits at .gitea/gitleaks.toml. A repository without that file is not scanned by this scanner. |
Options
Section titled “Options”| Option | Description |
|---|---|
| Paths | Limit the scanner to these paths, one pattern per line, for example src/**. Blank scans the whole repository. |
| Built-in rules | Enable or disable each built-in rule. |
| Custom rules | A JSON array of rules, for example [{"id":"internal-token","name":"Internal token","regex":"...","severity":"high"}]. |
| Allowed paths | Paths the scanner does not read, for example testdata/**. |
| Allowed matches | Regular expressions matched against the value of a finding. A match is not reported. |
| Allowed findings | Findings you do not want reported, named by the fingerprint shown on the finding page. |
| Read the history of the branch | Also reads the commits before the tip of the branch. A secret that a later commit removed is still committed and still has to be rotated. |
| Refuse a push that introduces a secret | Turns on secret protection, see below. |
The Scan the history button on the settings page re-reads the whole history of every scanned branch instead of only what changed since the last scan. Cleanup removes findings of branches that no longer exist. The settings page also lists the recent scan runs with the commit, status and the number of findings found, added and fixed, and lets you retry a failed run.
Ignore file
Section titled “Ignore file”A repository can keep its exceptions in the code, where they are reviewed and versioned. Create .gitea/secret-scan-ignore with one entry per line. Lines starting with # are comments. An entry is a path (a file, a directory or a glob such as third_party or **/*.env) or the 64-character fingerprint of a finding. The file is limited to 64 KiB and 1000 entries. Both secret scanners read it.
Findings
Section titled “Findings”Open the Security tab of a repository and select Secrets. Each finding shows the rule, the secret type, the file and line, a masked match, a hash of the value, the entropy and the fingerprint. The secret itself is never stored, only a masked preview and a hash of it.
You can filter by status (open, closed, dismissed), severity, branch, rule and file path. Users with write access to the security unit can dismiss a finding with a reason (a fix has already been started, no bandwidth to fix this, risk is tolerable, the finding is inaccurate, only used in tests) and reopen it. A finding closes when a later scan no longer finds it. A finding does not close just because the secret was removed in a later commit when history scanning is enabled: the credential is still in the history and has to be rotated.
Secret protection
Section titled “Secret protection”When Refuse a push that introduces a secret is enabled for the repository, every push is read before the refs move. Only the lines the push adds are read, so a secret that was already in a file is not blamed on the push, and a force push is read for what it restores.
A refused push names the rule, file and line of each secret with a masked preview. The secret itself is never printed or logged.
To measure the false positive rate before refusing anything, enable Only say what would be refused. The push goes through and the audit log records what would have been refused.
A repository administrator can push anyway and give a reason:
git push -o security.push-protection.bypass="test fixture, rotated" origin mainRefusals, would-have-been refusals and bypasses are written to the audit log.
The check is bounded, so it never makes a push wait for long: a push with more than 200 new commits or 20,000 added lines, or one that takes longer than 10 seconds to read, is let through unread. The scan that follows the push still records the finding, so the secret does not become invisible, but it is not refused. Only scanners that finish within the time of a push offer protection: the built-in scanner and the Gitleaks ruleset (read from the state of the repository before the push, so one push cannot delete the ruleset and add a secret at the same time).
Findings of all types, including secrets, are available through the API with a token that has the security scope:
| Endpoint | Description |
|---|---|
GET /repos/{owner}/{repo}/security/findings |
List findings. |
GET /repos/{owner}/{repo}/security/findings/{index} |
Get a finding. |
POST /repos/{owner}/{repo}/security/findings/{index}/dismiss |
Dismiss a finding. |
POST /repos/{owner}/{repo}/security/findings/{index}/reopen |
Reopen a finding. |
GET /repos/{owner}/{repo}/security/findings/sarif |
Export the findings as SARIF. |
Agents
Section titled “Agents”A security agent can judge the findings of every scanner, secrets included, as real or false positive, and the verdict is shown on the finding (Triage with agent on the finding page asks for one). When a secret is confirmed, rotate it: removing it from the code does not make it secret again.