feat: report Actuator endpoints that exposure and access together reach - #47
Open
vianbas wants to merge 1 commit into
Open
feat: report Actuator endpoints that exposure and access together reach#47vianbas wants to merge 1 commit into
vianbas wants to merge 1 commit into
Conversation
sprig read management.endpoints.web.exposure.include and stopped there, which is half a gate. Measured against running apps on Boot 2.3.12, 3.3.13 and 3.5.16, neither half reaches a disabled-by-default endpoint on its own: under include: "*" alone, POST /actuator/shutdown answers 404 on all three, and under include: health,info with shutdown.access=unrestricted it answers 404 as well. Name the endpoint in the exposure list and open the gate, and the same request answers 200 and the process exits. SPR-CONFIG-006 reports that pair, at CRITICAL. It reads both spellings Boot honours, per-endpoint and blanket, because sprig does not read pom.xml and has no idea which Boot version it is looking at. access arrived in 3.4 and is inert before it; enabled was honoured on all three versions measured. Three measurements shaped the rule rather than the report in #45: - read-only is enough for heapdump, a GET. Only shutdown, a POST, needs unrestricted. Keying on unrestricted alone would have missed the disclosure. - access without exposure reaches nothing. #45 says otherwise. It answers 404, reproduced twice, with the named-exposure control at 200. Firing on the access property alone would have shipped a false positive of the kind #42 removed. - env, configprops, beans, mappings and threaddump answer 200 from exposure alone on every version, so an access property on them grants no reachability the exposure list has not. #45 proposed covering them here; they belong to SPR-CONFIG-001. SPR-CONFIG-001 loses the shutdown token in the same change. Exposure never reached that endpoint on any version measured, so it was a HIGH finding with nothing behind it. Its doc now splits the heapdump claim by version: served by exposure alone through 3.3, held at 404 from 3.4 until something opens the gate. The README claim of zero false-positive noise goes with it. A rule firing on an unreachable endpoint was noise, and what the project actually does is treat false positives as bugs. Suite 59 to 66. Golden regenerated: one new rules-table entry at security-severity 9.0, one description change, and the rule index shift. Closes #45
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds SPR-CONFIG-006 (CRITICAL): an Actuator endpoint that Boot disables by
default is both exposed over HTTP and switched back on. Removes the
shutdowntoken from SPR-CONFIG-001, which could never reach anything. Splits
SPR-CONFIG-001's heapdump claim by Boot version.
access/enabledaccess/enabledshutdowninexposure.includeWhy
Closes #45
sprig read
management.endpoints.web.exposure.includeand stopped there. Thatis half a gate. Neither half reaches a disabled-by-default endpoint alone.
Every cell below is an observed HTTP status against a running app
(
spring-boot-starter-web+spring-boot-starter-actuator), withexposure.include: "*". Each cell isheapdump/shutdown.endpoint.<id>.enabled: trueendpoints.enabled-by-default: trueendpoint.<id>.access: unrestrictedendpoint.<id>.access: read-onlyendpoints.access.default: unrestrictedendpoints.access.max-permittedThree places the measurements corrected #45
accesswithout exposure reaches nothing. #45 states thatexposure.include: health,infoplusheapdump.access: unrestrictedserves theheap dump. It does not: 404, reproduced twice, with the control at 200 once the
id is added to the include list. The two gates are AND. A rule keyed on the
access property alone would have been a false positive of the kind #42 removed.
read-onlyis enough to leak.heapdumpis a GET, soread-onlyservesit. Only
shutdown, a POST, needsunrestricted. Keying onunrestrictedalone, as #45 suggests, would have missed the disclosure.
env,configprops,beans,mappings,threaddumpare out of scope.All five answer 200 from exposure alone on every version, so an
accessproperty on them grants nothing new. #45 proposed covering them; they are
SPR-CONFIG-001's finding.
max-permittedis honoured, and caps writes only:read-onlytakesshutdownback to 404 while
heapdumpkeeps serving a real HPROF. The rule's oneknowing miss is documented rather than hidden: the cap does nothing before 3.4,
so a pre-3.4 project setting both
shutdown.enabled: trueand a cap staysreachable while the rule is quiet. Reading the cap as inert instead would put a
CRITICAL finding on every correctly capped 3.4+ project.
How was this verified?
Probes. Every row above is a separate JVM start against a real app, each
configuration run twice with identical results. HPROF responses were confirmed
by the
JAVA PROFILE 1.0.2header rather than by byte count, and each shutdown200 was confirmed by the process exiting.
Tests. 59 to 66.
mvn -B -ntp clean verifyrun twice,BUILD SUCCESSbothtimes, spotless clean across 75 files.
Five new fixtures, one per measured fact: both gates open, access without
exposure, the
max-permittedcap, the blanket default with a per-endpointoverride, and
shutdownalone in the exposure list. Each fixture carries theversion and status codes it encodes as a comment, so a behaviour change is a
change to both.
Against the config that started the report. halo's actuator block,
reconstructed:
The two lines #45 reports as invisible are the two new findings.
Dogfood scan (the command CI runs) reports the same single pre-existing
NoOpPasswordEncoderRule.java:91self-match, exit 1. No new self-findings.Goldens regenerated with
-DupdateGoldens=trueand reviewed as a diff: onenew rules-table entry at
security-severity9.0, SPR-CONFIG-001's descriptionlosing
shutdown, and the rule index shift. No finding in demo-app changes.Notes for review
SARIF (
error, 9.0), the console renderer and--fail-on, and nothing usedit. A project running
--fail-on CRITICALin CI will start failing on this,which is the intent.
management.endpoint.<id>.accessand.enabledare bound reflectively perendpoint id and appear in no metadata release, so they go in
ACCEPTED_ABSENCESwith a measured observation each. The blanket properties(
access.default,access.max-permitted,enabled-by-default) are declaredand need no entry.
Base and profile files are never merged.
envand its neighbours answer 200 on everyversion measured, and
/actuator/envalone hands over credentials. Theversion-dependent claim was about heapdump, and that is what the doc now
splits.
Checklist
mvn verifypasses locallyREADME.md,docs/rules/*.md) if user-facing behavior changeddocs/rules/