doc/user/application_security/secret_detection/automatic_response.md
{{< details >}}
{{< /details >}}
GitLab secret detection automatically responds when it finds certain types of leaked secrets. Automatic responses can:
GitLab supports automatic response for the following types of secrets:
| Secret type | Action taken | Supported on GitLab.com | Supported in GitLab Self-Managed |
|---|---|---|---|
| GitLab personal access tokens | Immediately revoke token, send email to owner. <sup>1</sup> | ✅ | ✅ |
| Amazon Web Services (AWS) IAM access keys | Notify AWS. | ✅ | ⚙ |
| Google Cloud service account keys, API keys, and OAuth client secrets | Notify Google Cloud. | ✅ | ⚙ |
| Postman API keys | Notify Postman. Postman notifies the key owner. | ✅ | ⚙ |
Footnotes:
gitlab_personal_access_token.Component legend:
{{< history >}}
{{< /history >}}
Credentials are only post-processed when secret detection finds them:
This diagram describes how a post-processing hook revokes a secret in the GitLab application:
%%{init: { "fontFamily": "GitLab Sans" }}%%
sequenceDiagram
accTitle: Architecture diagram
accDescr: How a post-processing hook revokes a secret in the GitLab application.
autonumber
GitLab Rails-->+GitLab Rails: gl-secret-detection-report.json
GitLab Rails->>+GitLab Sidekiq: StoreScansService
GitLab Sidekiq-->+GitLab Sidekiq: ScanSecurityReportSecretsWorker
GitLab Sidekiq-->+GitLab token revocation API: GET revocable keys types
GitLab token revocation API-->>-GitLab Sidekiq: OK
GitLab Sidekiq->>+GitLab token revocation API: POST revoke revocable keys
GitLab token revocation API-->>-GitLab Sidekiq: ACCEPTED
GitLab token revocation API-->>+Partner API: revoke revocable keys
Partner API-->>+GitLab token revocation API: ACCEPTED
GitLab notifies partners when credentials they issue are leaked in public repositories on GitLab.com. If you operate a cloud or SaaS product and you're interested in receiving these notifications, learn more in epic 4944. Partners must implement a partner API, which is called by the GitLab token revocation API.
A partner API integrates with the GitLab token revocation API to receive and respond to leaked token revocation requests. The service should be a publicly accessible HTTP API that is idempotent and rate-limited.
Requests to your service can include one or more leaked tokens, and a header with the signature of the request body. We strongly recommend that you verify incoming requests using this signature, to prove it's a genuine request from GitLab. The diagram below details the necessary steps to receive, verify, and revoke leaked tokens:
%%{init: { "fontFamily": "GitLab Sans" }}%%
sequenceDiagram
accTitle: Partner API data flow
accDescr: How a partner API should receive and respond to leaked token revocation requests.
autonumber
GitLab token revocation API-->>+Partner API: Send new leaked credentials
Partner API-->>+GitLab public keys endpoint: Get active public keys
GitLab public keys endpoint-->>+Partner API: One or more public keys
Partner API-->>+Partner API: Verify request is signed by GitLab
Partner API-->>+Partner API: Respond to leaks
Partner API-->>+GitLab token revocation API: HTTP status
This JSON schema document describes the body of the revocation request:
{
"type": "array",
"items": {
"description": "A leaked token",
"type": "object",
"properties": {
"type": {
"description": "The type of token. This is vendor-specific and can be customized to suit your revocation service",
"type": "string",
"examples": [
"my_api_token"
]
},
"token": {
"description": "The substring that was matched by the secret detection analyzer. In most cases, this is the entire token itself",
"type": "string",
"examples": [
"XXXXXXXXXXXXXXXX"
]
},
"url": {
"description": "The URL to the raw source file hosted on GitLab where the leaked token was detected",
"type": "string",
"examples": [
"https://gitlab.example.com/some-repo/-/raw/abcdefghijklmnop/compromisedfile1.java"
]
}
}
}
}
Example:
[{"type": "my_api_token", "token": "XXXXXXXXXXXXXXXX", "url": "https://example.com/some-repo/-/raw/abcdefghijklmnop/compromisedfile1.java"}]
In this example, secret detection has determined that an instance of my_api_token has been leaked. The
value of the token is provided to you, in addition to a publicly accessible URL to the raw content of the
file containing the leaked token.
The request includes two special headers:
| Header | Type | Description |
|---|---|---|
Gitlab-Public-Key-Identifier | string | A unique identifier for the key pair used to sign this request. Primarily used to aid in key rotation. |
Gitlab-Public-Key-Signature | string | A base64-encoded signature of the request body. |
You can use these headers along with the GitLab Public Keys endpoint to verify that the revocation request was genuine.
GitLab maintains a publicly-accessible endpoint for retrieving public keys used to verify revocation requests. The endpoint can be provided on request.
This JSON schema document describes the response body of the public keys endpoint:
{
"type": "object",
"properties": {
"public_keys": {
"description": "An array of public keys managed by GitLab used to sign token revocation requests.",
"type": "array",
"items": {
"type": "object",
"properties": {
"key_identifier": {
"description": "A unique identifier for the keypair. Match this against the value of the Gitlab-Public-Key-Identifier header",
"type": "string"
},
"key": {
"description": "The value of the public key",
"type": "string"
},
"is_current": {
"description": "Whether the key is currently active and signing new requests",
"type": "boolean"
}
}
}
}
}
}
Example:
{
"public_keys": [
{
"key_identifier": "6917d7584f0fa65c8c33df5ab20f54dfb9a6e6ae",
"key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEN05/VjsBwWTUGYMpijqC5pDtoLEf\nuWz2CVZAZd5zfa/NAlSFgWRDdNRpazTARndB2+dHDtcHIVfzyVPNr2aznw==\n-----END PUBLIC KEY-----\n",
"is_current": true
}
]
}
You can check whether a revocation request is genuine by verifying the Gitlab-Public-Key-Signature header
against the request body, using the corresponding public key taken from the API response above. We use
ECDSA with SHA256 hashing to
produce the signature, which is then base64-encoded into the header value.
The Python script below demonstrates how the signature can be verified. It uses the popular pyca/cryptography module for cryptographic operations:
import hashlib
import base64
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.serialization import load_pem_public_key
from cryptography.hazmat.primitives.asymmetric import ec
public_key = str.encode("") # obtained from the public keys endpoint
signature_header = "" # obtained from the `Gitlab-Public-Key-Signature` header
request_body = str.encode(r'') # obtained from the revocation request body
pk = load_pem_public_key(public_key)
decoded_signature = base64.b64decode(signature_header)
pk.verify(decoded_signature, request_body, ec.ECDSA(hashes.SHA256())) # throws if unsuccessful
print("Signature verified!")
The main steps are:
Gitlab-Public-Key-Signature header value.