Skip to content

Commit 509bba2

Browse files
committed
Add curated checks for exposed credential files and Spring Actuator
Two read-only premium checks drawn from watching how AI pentest agents probe a site. Both only report when the response carries a real marker, never on a bare 200, so they do not add false positives. Exposed credential or private key file: tries the well known paths for AWS, Google Cloud, Docker and s3cmd credential files and for SSH and TLS private keys, and reports one only when the body actually holds a credential marker, told apart from the site's not found page by a control. A leaked key is signed in with, no guessing, which is how several large breaches began. Spring Boot Actuator exposed: tries the actuator paths and reports when the answer is an actuator payload, the env or configprops configuration that carries database passwords and API keys, the index that advertises heapdump, or the bean list. An open actuator hands an outsider the service's secrets.
1 parent 210d3c4 commit 509bba2

2 files changed

Lines changed: 76 additions & 0 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"id": "misconfiguration-cloud-credentials-file-exposed",
3+
"class": "misconfiguration",
4+
"safety": "read",
5+
"severity_floor": "high",
6+
"title": "A cloud credential or private key file is exposed",
7+
"summary": "A file that holds cloud credentials or a private key is being served to anyone. An outsider who reads an AWS, Google Cloud, Docker or s3cmd credential file, or an SSH or TLS private key, can sign in to the account or service it belongs to with no guessing, which is how several large breaches began. This check only reports the file when its body actually carries a credential marker, so a plain not-found page is never a finding.",
8+
"needs": [],
9+
"candidate_paths": [
10+
"/.aws/credentials",
11+
"/.aws/credentials.bak",
12+
"/.aws/config",
13+
"/.config/gcloud/application_default_credentials.json",
14+
"/application_default_credentials.json",
15+
"/service-account.json",
16+
"/gcp-credentials.json",
17+
"/google-credentials.json",
18+
"/.docker/config.json",
19+
"/.s3cfg",
20+
"/.boto",
21+
"/.ssh/id_rsa",
22+
"/.ssh/id_ed25519",
23+
"/secrets.json",
24+
"/credentials.json"
25+
],
26+
"probe": [
27+
{ "request": { "method": "GET", "path": "{route}" } }
28+
],
29+
"confirm": {
30+
"control": "A path that cannot exist, so the site's not found answer is known and a credential file is told apart from a soft 404 or a catch-all page.",
31+
"differential": "status == 200 and (body_contains(\"aws_access_key_id\") or body_contains(\"aws_secret_access_key\") or (body_contains(\"\\\"private_key\\\"\") and body_contains(\"\\\"client_email\\\"\")) or (body_contains(\"\\\"auths\\\"\") and body_contains(\"\\\"auth\\\"\")) or (body_contains(\"access_key\") and body_contains(\"secret_key\")) or body_contains(\"PRIVATE KEY-----\")) and body_differs(control)",
32+
"retest": 2
33+
},
34+
"reproduce": "curl -sk 'https://host/.aws/credentials' (and the other candidate paths this check tried) and read the body. An AWS file shows aws_access_key_id and aws_secret_access_key; a Google service account shows \"private_key\" and \"client_email\"; a Docker config shows \"auths\" with an \"auth\" token; an s3cmd or boto file shows access_key and secret_key; an SSH or TLS key shows a PRIVATE KEY----- block. If any returns the secret, treat it as live and rotate it.",
35+
"remediate": "Remove the file from the web root and from anything the server will serve, then rotate every credential it exposed, since it must be assumed to have been read. Serve application code from a directory that does not include dotfiles or deployment artifacts, and add a rule that denies requests for credential and key files. Keep secrets in a secret manager or environment, never in a file under the document root.",
36+
"references": [],
37+
"mappings": {
38+
"cwe": "CWE-798",
39+
"owasp": "A05:2021"
40+
},
41+
"rulesets": ["secret-files"]
42+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"id": "misconfiguration-spring-actuator-exposed",
3+
"class": "misconfiguration",
4+
"safety": "read",
5+
"severity_floor": "high",
6+
"title": "Spring Boot Actuator is exposed, leaking configuration and secrets",
7+
"summary": "A Spring Boot Actuator endpoint is answering without a login. The env and configprops endpoints print the application's configuration, which usually includes database passwords, API keys and other secrets, and the heapdump endpoint hands over a full memory dump that carries every secret the process holds. An outsider who reaches these reads the credentials and can often move on to take over the service. This check only reports it when the response is an actuator payload, not a plain page.",
8+
"needs": [],
9+
"candidate_paths": [
10+
"/actuator",
11+
"/actuator/env",
12+
"/actuator/configprops",
13+
"/actuator/beans",
14+
"/actuator/mappings",
15+
"/api/actuator",
16+
"/api/actuator/env"
17+
],
18+
"probe": [
19+
{ "request": { "method": "GET", "path": "{route}" } }
20+
],
21+
"confirm": {
22+
"control": "A path that cannot exist, so the site's not found answer is known and an actuator payload is told apart from a soft 404 or a catch-all page.",
23+
"differential": "status == 200 and ((body_contains(\"\\\"propertySources\\\"\") and body_contains(\"\\\"activeProfiles\\\"\")) or (body_contains(\"\\\"_links\\\"\") and body_contains(\"\\\"heapdump\\\"\")) or (body_contains(\"\\\"_links\\\"\") and body_contains(\"\\\"self\\\"\") and body_contains(\"\\\"env\\\"\")) or (body_contains(\"\\\"contexts\\\"\") and body_contains(\"\\\"beans\\\"\"))) and body_differs(control)",
24+
"retest": 2
25+
},
26+
"reproduce": "curl -sk 'https://host/actuator' and read the JSON: an exposed actuator answers with a \"_links\" list that names env, configprops, beans and often heapdump. Then curl -sk 'https://host/actuator/env' for the configuration (look for \"propertySources\" and \"activeProfiles\"), where database passwords and API keys usually sit. If 'https://host/actuator/heapdump' downloads a file, the whole process memory, with every secret in it, is readable.",
27+
"remediate": "Do not expose actuator to the internet. Set management.endpoints.web.exposure.include to only the endpoints you need (health and info at most), put the management port behind the firewall or on a separate internal interface, and require authentication on the actuator path. Rotate any secret that env, configprops or heapdump could have shown, since they must be assumed read.",
28+
"references": [],
29+
"mappings": {
30+
"cwe": "CWE-200",
31+
"owasp": "A05:2021"
32+
},
33+
"rulesets": ["spring-boot"]
34+
}

0 commit comments

Comments
 (0)