You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Related:#44. The detection half of this report cannot be implemented until that lands,
because ConfigKeyMetadataTest rejects the key it needs. Found by scanning halo-dev/halo at a559d15.
Config that is missed
application/src/main/resources/application.yaml:
management:
endpoints:
web:
exposure:
include: "*"# line 80, sprig reports thisendpoint:
shutdown:
access: unrestricted # line 83, sprig says nothingheapdump:
access: unrestricted # line 85, sprig says nothing
$ sprig scan haloSPR-CONFIG-001 [HIGH] application/src/main/resources/application-dev.yaml:49 Actuator endpoint(s) exposed: *.SPR-CONFIG-002 [MEDIUM] application/src/main/resources/application-mariadb.yaml:5 Hardcoded secret in configuration: spring.r2dbc.password.SPR-CONFIG-002 [MEDIUM] application/src/main/resources/application-mysql.yaml:5 Hardcoded secret in configuration: spring.r2dbc.password.SPR-CONFIG-002 [MEDIUM] application/src/main/resources/application-postgresql.yaml:5 Hardcoded secret in configuration: spring.r2dbc.password.SPR-CONFIG-002 [MEDIUM] application/src/main/resources/application.yaml:13 Hardcoded secret in configuration: spring.r2dbc.password.SPR-CONFIG-001 [HIGH] application/src/main/resources/application.yaml:80 Actuator endpoint(s) exposed: *.Checked 1349 Java file(s), 8 config file(s) in 2268 ms. Found 6 finding(s), 4 medium, 2 high.
Line 80 is the only finding touching the actuator block above, and nothing in the run mentions
lines 83 or 85. The two properties that turn the wildcard from an information leak into a remote
kill switch and a memory dump are invisible to sprig.
The access gate is real and arrived in 3.4.0
Boot 3.4.0 introduced management.endpoint.<id>.access (none / read-only / unrestricted) as a gate that sits afterexposure.include, deprecating management.endpoints.enabled-by-default in favour of management.endpoints.access.default.
From the metadata of spring-boot-actuator-autoconfigure:
Every row below used spring-boot-starter-web + spring-boot-starter-actuator with management.endpoints.web.exposure.include=*. Each row is its own JVM start. HPROF sizes vary
between runs, so the header is what proves the dump is real rather than the byte count.
Boot
Extra config
/actuator/env
GET /actuator/heapdump
POST /actuator/shutdown
2.3.12
none
200
200, JAVA PROFILE 1.0.2
404
2.3.12
...shutdown.enabled=true
200
3.3.13
none
200
200, JAVA PROFILE 1.0.2
404
3.5.16
none
200
404
404
3.5.16
...heapdump.access=unrestricted
200, JAVA PROFILE 1.0.2
3.5.16
...shutdown.access=unrestricted
200, process exits
3.5.16
...access=none on both
200
404
404
configprops, beans and mappings also return 200 under the wildcard alone on 3.3.13 and
3.5.16.
Three problems fall out of that table
1. The miss
On Boot 3.4+, access: unrestricted is the property that makes the endpoint reachable, and
sprig does not read it. A project with exposure.include: health,info and management.endpoint.heapdump.access: unrestricted gets no finding at all while the heap dump
is served. halo sets both the wildcard and access, so sprig reports the less serious half of
its configuration and stays silent on the worse half.
2. The heapdump claim is version-dependent
docs/rules/SPR-CONFIG-001.md states that /actuator/heapdump "leaks process memory — including
tokens and keys". True through 3.3, false from 3.4 without access. The env half of the same
sentence holds on every version measured.
3. The bare shutdown token looks like a false positive
ActuatorExposureRule treats shutdown in exposure.include as a sensitive token worth a HIGH
finding. Exposure alone never reached that endpoint on any version measured: 404 on 2.3.12,
3.3.13 and 3.5.16 alike. It needs shutdown.enabled=true through 3.3, or shutdown.access=unrestricted from 3.4, because the endpoint is disabled by default in every
release. Adding --management.endpoint.shutdown.enabled=true to the 2.3.12 probe turned the
same request from 404 into 200, which is the control for that claim.
exposure.include: shutdown on its own is therefore a HIGH finding with nothing behind it.
Suggested detection
Read management.endpoint.<id>.access. unrestricted on a sensitive id (shutdown, heapdump, env, threaddump) is the signal, as is the blanket management.endpoints.access.default: unrestricted. For Boot 2.x through 3.3 the equivalent
is management.endpoint.<id>.enabled: true. Note that management.endpoint.shutdown.access
is absent from Spring's own configuration metadata, so [bug]: ConfigKeyMetadataTest treats absence from Spring's metadata as proof a property does not exist #44 has to land first.
Split the SPR-CONFIG-001 doc by version, the way SPR-CONFIG-004's doc now does. The wildcard
leaks env, configprops, beans and mappings across the whole supported range. It leaks
heap dumps through 3.3, and from 3.4 only when access is also set.
Drop the bare shutdown token, or pair it with the property that actually enables the
endpoint.
Severity is worth deciding here rather than inheriting. The wildcard alone on Boot 3.4+ is an
information leak, not memory disclosure and not remote shutdown. Whether that is still HIGH, and
whether access: unrestricted on shutdown deserves CRITICAL, are different questions from the
one the rule answers today.
Environment
sprig version: sprig 0.1.0, at 80fd14e
Java version: openjdk version "17.0.20" 2026-07-21 (Homebrew, build 17.0.20+0)
Probes: Boot 2.3.12.RELEASE, 3.3.13 and 3.5.16, spring-boot-starter-web + spring-boot-starter-actuator, no actuator configuration beyond the columns shown
Metadata read from spring-boot-actuator-autoconfigure 3.2.12, 3.3.13, 3.4.0, 3.4.1, 3.5.16
Scan target: halo at a559d15, which builds on Spring Boot 4.1.0
Related: #44. The detection half of this report cannot be implemented until that lands,
because
ConfigKeyMetadataTestrejects the key it needs. Found by scanninghalo-dev/halo at
a559d15.Config that is missed
application/src/main/resources/application.yaml:Line 80 is the only finding touching the actuator block above, and nothing in the run mentions
lines 83 or 85. The two properties that turn the wildcard from an information leak into a remote
kill switch and a memory dump are invisible to sprig.
The
accessgate is real and arrived in 3.4.0Boot 3.4.0 introduced
management.endpoint.<id>.access(none/read-only/unrestricted) as a gate that sits afterexposure.include, deprecatingmanagement.endpoints.enabled-by-defaultin favour ofmanagement.endpoints.access.default.From the metadata of
spring-boot-actuator-autoconfigure:accessfamily declaredconditions.access,access.default,access.max-permittedenabled-by-default→access.defaultEvidence: measured against running apps
Every row below used
spring-boot-starter-web+spring-boot-starter-actuatorwithmanagement.endpoints.web.exposure.include=*. Each row is its own JVM start. HPROF sizes varybetween runs, so the header is what proves the dump is real rather than the byte count.
/actuator/envGET /actuator/heapdumpPOST /actuator/shutdownJAVA PROFILE 1.0.2...shutdown.enabled=trueJAVA PROFILE 1.0.2...heapdump.access=unrestrictedJAVA PROFILE 1.0.2...shutdown.access=unrestricted...access=noneon bothconfigprops,beansandmappingsalso return 200 under the wildcard alone on 3.3.13 and3.5.16.
Three problems fall out of that table
1. The miss
On Boot 3.4+,
access: unrestrictedis the property that makes the endpoint reachable, andsprig does not read it. A project with
exposure.include: health,infoandmanagement.endpoint.heapdump.access: unrestrictedgets no finding at all while the heap dumpis served. halo sets both the wildcard and
access, so sprig reports the less serious half ofits configuration and stays silent on the worse half.
2. The heapdump claim is version-dependent
docs/rules/SPR-CONFIG-001.mdstates that/actuator/heapdump"leaks process memory — includingtokens and keys". True through 3.3, false from 3.4 without
access. Theenvhalf of the samesentence holds on every version measured.
3. The bare
shutdowntoken looks like a false positiveActuatorExposureRuletreatsshutdowninexposure.includeas a sensitive token worth a HIGHfinding. Exposure alone never reached that endpoint on any version measured: 404 on 2.3.12,
3.3.13 and 3.5.16 alike. It needs
shutdown.enabled=truethrough 3.3, orshutdown.access=unrestrictedfrom 3.4, because the endpoint is disabled by default in everyrelease. Adding
--management.endpoint.shutdown.enabled=trueto the 2.3.12 probe turned thesame request from 404 into 200, which is the control for that claim.
exposure.include: shutdownon its own is therefore a HIGH finding with nothing behind it.Suggested detection
management.endpoint.<id>.access.unrestrictedon a sensitive id (shutdown,heapdump,env,threaddump) is the signal, as is the blanketmanagement.endpoints.access.default: unrestricted. For Boot 2.x through 3.3 the equivalentis
management.endpoint.<id>.enabled: true. Note thatmanagement.endpoint.shutdown.accessis absent from Spring's own configuration metadata, so [bug]: ConfigKeyMetadataTest treats absence from Spring's metadata as proof a property does not exist #44 has to land first.
leaks
env,configprops,beansandmappingsacross the whole supported range. It leaksheap dumps through 3.3, and from 3.4 only when
accessis also set.shutdowntoken, or pair it with the property that actually enables theendpoint.
Severity is worth deciding here rather than inheriting. The wildcard alone on Boot 3.4+ is an
information leak, not memory disclosure and not remote shutdown. Whether that is still HIGH, and
whether
access: unrestrictedonshutdowndeserves CRITICAL, are different questions from theone the rule answers today.
Environment
sprig 0.1.0, at80fd14eopenjdk version "17.0.20" 2026-07-21(Homebrew, build 17.0.20+0)spring-boot-starter-web+spring-boot-starter-actuator, no actuator configuration beyond the columns shownspring-boot-actuator-autoconfigure3.2.12, 3.3.13, 3.4.0, 3.4.1, 3.5.16a559d15, which builds on Spring Boot 4.1.0