fix(modules): guard ignition, web.config and appsettings against soft-404 shells (#286)

This commit is contained in:
Tigah
2026-07-22 12:45:48 -07:00
committed by GitHub
parent 251be8481e
commit 9be3d4a51c
6 changed files with 61 additions and 3 deletions
@@ -141,6 +141,15 @@ func TestAppConfigExposureModules(t *testing.T) {
}
})
t.Run("an appsettings docs page that quotes ConnectionStrings and Password= is not a leak", func(t *testing.T) {
body := `<!DOCTYPE html><html><head><title>schema</title></head><body>` +
`<pre>{ "ConnectionStrings": "string", "note": "e.g. Server=x;Password=changeme;" }</pre>` +
`</body></html>`
if res := runAppCfgModule(t, appsettings, 200, body); len(res.Findings) > 0 {
t.Errorf("an html docs page should not match, got %d findings", len(res.Findings))
}
})
t.Run("prose that names the wp-config password is not a backup", func(t *testing.T) {
body := "set the DB_PASSWORD env var before running the installer"
if res := runAppCfgModule(t, wpconfig, 200, body); len(res.Findings) > 0 {
+9
View File
@@ -103,6 +103,15 @@ func TestDebugExposureModules(t *testing.T) {
}
})
t.Run("an spa fallback shell inlining the ignition client bundle is not the endpoint", func(t *testing.T) {
body := `<!DOCTYPE html><html><head><title>App</title></head><body><div id="app"></div>` +
`<script>function checkIgnition(r){return r.can_execute_commands;}` +
`/* bundled from vendor/facade/ignition */window.__spa_fallback=true;</script></body></html>`
if res := runDebugModule(t, ignition, 200, body); len(res.Findings) > 0 {
t.Errorf("a bundled js property reference should not match, got %d findings", len(res.Findings))
}
})
t.Run("a plain 200 body is not a leak", func(t *testing.T) {
for _, file := range []string{ignition, profiler, heapdump} {
if res := runDebugModule(t, file, 200, "<html><body>plain</body></html>"); len(res.Findings) > 0 {
@@ -111,6 +111,15 @@ func TestWebserverConfigExposureModules(t *testing.T) {
}
})
t.Run("a docs page that embeds a raw web.config sample is not flagged", func(t *testing.T) {
body := `<!DOCTYPE html><html><head><title>IIS docs</title></head><body>` +
`<p>example: <configuration><connectionStrings><add name="x"/></connectionStrings></configuration></p>` +
`</body></html>`
if res := runWebSrvModule(t, webconfig, 200, body); len(res.Findings) > 0 {
t.Errorf("an html docs page should not match, got %d findings", len(res.Findings))
}
})
t.Run("an html page is not an htaccess", func(t *testing.T) {
body := "<html><head><title>x</title></head><body>RewriteEngine On AuthType Basic</body></html>"
if res := runWebSrvModule(t, htaccess, 200, body); len(res.Findings) > 0 {
+10
View File
@@ -37,6 +37,16 @@ http:
- "pwd="
- "AccountKey="
# a docs/schema page that quotes the same json keys as a code sample trips
# the two matchers above with no real appsettings.json present. suppress
# any response that opens like an html document; a real appsettings.json
# is a plain json object and carries no markup.
- type: regex
part: body
negative: true
regex:
- '(?i)<(!doctype|html|head|title|body)[ >]'
extractors:
- type: regex
name: connection_string
+14 -3
View File
@@ -20,10 +20,21 @@ http:
status:
- 200
- type: word
# an spa fallback route that inlines the ignition client bundle references
# can_execute_commands as a bare js property with no real health-check
# response present. anchor on the actual json shape the endpoint emits
# (a quoted key immediately followed by a boolean), which a bundled script
# accessing the field as `r.can_execute_commands` never produces.
- type: regex
part: body
words:
- "can_execute_commands"
regex:
- '"can_execute_commands"\s*:\s*(?:true|false)'
- type: regex
part: body
negative: true
regex:
- '(?i)<(!doctype|html|head|title|body)[ >]'
extractors:
- type: regex
+10
View File
@@ -34,6 +34,16 @@ http:
- "<system.webServer"
- "<appSettings"
# a docs page that embeds a raw web.config sample as an example trips both
# matchers above with no real web.config present. suppress any response
# that opens like an html document; a real web.config is a plain xml
# document rooted at <configuration> and never carries html markup.
- type: regex
part: body
negative: true
regex:
- '(?i)<(!doctype|html|head|title|body)[ >]'
extractors:
- type: regex
name: connection_string