Skip to content

security: harden schema metadata queries and Ref deserialization#243

Merged
zantvoort merged 2 commits into
mainfrom
security/1.13-hardening
Jul 12, 2026
Merged

security: harden schema metadata queries and Ref deserialization#243
zantvoort merged 2 commits into
mainfrom
security/1.13-hardening

Conversation

@zantvoort

Copy link
Copy Markdown
Collaborator

A security audit ahead of the 1.13 release, run as three parallel sweeps (SQL construction, deserialization/reflection, logging/CI/supply-chain). No exploitable vulnerability was found in a correctly-using application. The framework's fundamentals held up: parameterized queries by construction, unsafe()-gated destructive DML, no bound-parameter values in logs/exceptions/observations, no credential logging, a zero-dependency CLI with no install hooks, and a tag-gated GPG-signed release pipeline. These are defense-in-depth hardening changes.

Changes

  • storm-core DatabaseSchema: the INFORMATION_SCHEMA and ALL_* metadata queries used by schema validation are built with bound parameters instead of escaped string literals. The catalog and schema names come from the JDBC connection (database-supplied) and were already correctly escaped by doubling quotes, so this is not a fix for an exploit; it removes SQL-text assembly from concatenated values entirely. Verified behavior-preserving against the 92-test schema-validation integration suite on H2.
  • storm-kotlinx-serialization: resolving a Ref's target class from a serializer now loads the class without initialization and rejects it unless it is a Storm Data type, before the class is used. Previously the class was initialized (static blocks run) before an unchecked as Class<out Data> cast that erases at runtime and validated nothing. The serial name is normally the declared entity type, so this hardens a path not reachable with hostile data in a normal application.
  • storm-test SqlCapture: javadoc notes that captured statements retain bound parameter values (potentially sensitive) and must not be routed to logs or external systems from production code.
  • Docs: the serialization guide warns that a loaded Ref serializes its full entity and recommends projections for response shapes that must not over-expose fields.

Assessment notes

Both automated sweeps flagged "critical" findings that did not survive review: the DatabaseSchema "injection" relied on an incorrect exploit (doubling single quotes is correct, complete SQL literal escaping, and the input is not user-controlled), and the kotlinx "RCE" requires an attacker to already control application serializer configuration rather than data. The hardening above is worth doing regardless, since a data-layer library should not assemble SQL from values or initialize arbitrary named classes.

Supply-chain hygiene (CI dependency scanning, GitHub Actions SHA-pinning) protects release integrity rather than library users and is tracked separately in #242.

Verification

Full reactor green (13,758 tests), including the schema-validation integration suites that exercise the converted metadata queries and the full kotlinx-serialization suite (192 tests) confirming the class-resolution change is behavior-preserving for legitimate types.

…ents

Two polish items surfaced by running the example applications on
Spring Boot 4.

- @DataStormTest provides an embedded test database on Spring Boot 4:
  a fallback auto-configuration in the slice activates only when Boot's
  own test-database replacement is absent (relocated to
  spring-boot-jdbc-test-autoconfigure in Boot 4), an embedded driver is
  on the test classpath, and spring.test.database.replace is not none.
  Ordered before the DataSource auto-configuration, whose back-off then
  applies naturally; inert on Boot 3. Slice tests behave identically on
  both generations without manual datasource properties.
- Trace-context SQL comments gain a sampled-only mode:
  TraceContextSqlCommenter(tracer, onlySampled) comments only
  statements of sampled traces, aligning the prepared-statement-caching
  cost with the correlation benefit when sampling is below 1.0. In the
  starters, storm.tracing.sql-comments accepts true or sampled, and
  unknown values fail startup with a descriptive error.

The docs also gain a composition warning: integration beans in user
configurations must be unconditional, because @ConditionalOnBean in a
plain @configuration evaluates before auto-configurations contribute
their beans and fails silently.

Fixes #238
Fixes #239
A security audit before the 1.13 release. No exploitable vulnerability
was found in a correctly-using application; these are defense-in-depth
hardening changes.

- storm-core DatabaseSchema: the INFORMATION_SCHEMA and ALL_* metadata
  queries used by schema validation are now built with bound parameters
  instead of escaped string literals. The catalog and schema names come
  from the JDBC connection (database-supplied) and were already escaped
  by doubling quotes, which is correct SQL literal escaping, so this is
  not a fix for an exploit; it removes SQL-text assembly from concatenated
  values entirely. Verified behavior-preserving against the schema
  validation integration suite.
- storm-kotlinx-serialization: resolving a Ref's target class from a
  serializer now loads the class without initialization and rejects it
  unless it is a Storm Data type, before the class is used. Previously
  the class was initialized (static blocks run) before the unchecked
  Data cast, which erases at runtime and validated nothing. The serial
  name is normally the declared entity type, so this hardens a path that
  is not reachable with hostile data in a normal application.
- storm-test SqlCapture gains a javadoc note that captured statements
  retain bound parameter values and must not be routed to logs or
  external systems from production code.
- Docs: the serialization guide warns that a loaded Ref serializes its
  full entity and recommends projections for response shapes that must
  not over-expose fields.
@zantvoort zantvoort merged commit 84e52f6 into main Jul 12, 2026
7 checks passed
@zantvoort zantvoort deleted the security/1.13-hardening branch July 12, 2026 09:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant