I scanned 50 open-source Spring Boot projects. More than half had silent config drift.
Source: Dev.to
What is config drift?
Spring Boot lets you define configuration per environment using profile files:
application.yml ← defaults
application-dev.yml ← overrides for development
application-staging.yml ← overrides for staging
application-prod.yml ← overrides for production
Config drift happens when a value in one profile diverges from the others in a way that wasn’t intentional.
It usually starts small: someone adds a setting to dev.yml for debugging, forgets about it, and three weeks later it’s in prod.yml because someone copy‑pasted the file as a starting point.
The tricky part: drift is silent. Your app starts, your tests pass, your CI is green. The misconfiguration just sits there, waiting.
The three patterns I see everywhere
1. The Actuator leak
This is the most common one, and arguably the most dangerous.
# application-dev.yml
management:
endpoints:
web:
exposure:
include: "*"
Reasonable in dev — you want all Actuator endpoints available for debugging.
The problem is when this value drifts into staging, and then into prod:
# application-prod.yml (drifted)
management:
endpoints:
web:
exposure:
include: "*" # ← exposes /actuator/env, /actuator/heapdump, …
Your /actuator/env endpoint now returns all environment variables — including secrets.
Your /actuator/heapdump lets anyone download a full JVM heap dump.
Spring Boot’s default is health,info. The moment you override it in dev and forget to restrict it in prod, you’ve created an information‑disclosure vulnerability with zero error messages and zero test failures.
2. The database schema destroyer
# application-dev.yml
spring:
jpa:
hibernate:
ddl-auto: update
update is convenient in development: Hibernate automatically adjusts your schema to match your entities.
It’s also one of the most dangerous settings you can have in production.
The safe production value is validate or none. But if update drifts from dev to prod and your entity model changes — Hibernate will silently modify your production schema. No migration script, no review, no warning.
I’ve seen this kill a production database.
3. The missing feature flag
# application-dev.yml
feature:
new-payment-flow:
enabled: true
# application-staging.yml
feature:
new-payment-flow:
enabled: true
# application-prod.yml
# ← key doesn't exist
When a key exists in dev and staging but not in prod, Spring Boot falls back to null (or throws a NullPointerException at runtime, if you’re lucky enough to have one).
This pattern is especially common with feature flags — they get added during development, tested on staging, and then forgotten when writing the prod config.
Why this is so hard to catch
- Code review won’t find it. You’re not comparing files side‑by‑side in a PR; you’re looking at the diff of what changed, not at the relationship between files.
- Your tests won’t find it. Unit tests run against a single profile. Integration tests typically run against a test profile. Nobody is running tests that compare what
dev.ymlsays vs. whatprod.ymlsays. - Your CI won’t find it. Your pipeline validates that the app starts and the tests pass. It doesn’t validate that
prod.ymlis consistent with your intentions.
The only way this surfaces is in production—usually at the worst possible moment.
Building a tool to catch it
I got tired of manually diffing YAML files before deployments. So I built spring‑drift, a CLI that scans your config directory, compares all profiles, and flags drift — specifically the dangerous kind.
$ spring-drift scan ./src/main/resources
✓ Found 4 profiles: default, dev, staging, prod
✗ 7 drift issues found
[DANGEROUS_DEFAULT] management.endpoints.web.exposure.include
default: health,info
dev: *
staging: *
prod: * ← matches dev — likely accidental
[DANGEROUS_DEFAULT] spring.jpa.hibernate.ddl-auto
default: validate
dev: update
prod: update ← destructive in production
[MISSING_KEY] feature.new-payment-flow.enabled
dev: true
staging: true
prod: ← will fall back to null
Report written to drift-report.md
It runs in ~26 ms on Linux, outputs a Markdown report you can paste directly into a PR, and knows about the most common dangerous Spring Boot defaults out of the box. It’s built with Java 21 + Picocli + GraalVM Native Image — a single binary, no JRE required.
How to add it to your workflow
The simplest integration is a pre‑deployment check:
# Before deploying to staging or prod:
spring-drift scan ./src/main/resources
If you want to fail the build on drift, use the exit code:
spring-drift scan ./src/main/resources || exit 1
Or add it to your GitHub Actions pipeline:
- name: Check config drift
run: spring-drift scan ./src/main/resources
curl -L https://github.com/jolle93/spring-boot-config-drift-detector/releases/latest/download/spring-drift-linux-x64 -o spring-drift
chmod +x spring-drift
./spring-drift scan ./src/main/resources
What I learned from scanning 50 open‑source projects
I ran spring‑drift against 50 well‑known Spring Boot projects on GitHub — from the official Spring PetClinic to large‑scale projects like mall, jhipster‑generated apps, and Apache projects such as ShenYu and DolphinScheduler.
26 out of 50 projects had at least one drift issue (53 %).
Across 497 individual modules scanned, the tool found:
| Category | Count |
|---|---|
| Total drift issues | 2 470 |
| Dangerous defaults | 167 |
| Missing keys | 2 172 |
| Value drifts | 131 |
Most common dangerous defaults
| Default | Occurrences | Notes |
|---|---|---|
management.endpoints.web.exposure.include | 78 modules | Flagged in the official Spring PetClinic – the reference app ships with include: *, exposing all Actuator endpoints unless overridden in a production profile. |
spring.datasource.password | 83 occurrences | Often empty or set to a dev‑only placeholder in production‑facing profiles. |
Observations
- The pattern is consistent across project sizes: small tutorial repos, large enterprise applications, and top‑level Apache projects all exhibit the same issues.
- Configuration files accumulate decisions over time and, unlike code, are rarely refactored.
Wrapping up
Config drift feels minor until it isn’t. The three patterns above — Actuator exposure, ddl-auto, and missing feature flags — have caused real outages in production systems. None are exotic edge cases.
Try spring‑drift on your own project
The tool is source‑available on GitHub and takes about 30 seconds to run against an existing Spring Boot project.
If you discover a dangerous default that isn’t covered yet, please open a Severity Rule Request.
Built with Java 21, Picocli, SnakeYAML, and GraalVM Native Image.
Available for Linux (x64) and macOS (arm64).