Skip to content

chore(security): update dependencies for open Dependabot alerts - #381

Merged
samgbafa merged 4 commits into
mainfrom
chore/security-dependency-update
Oct 19, 2026
Merged

samgbafa merged 4 commits into
mainfrom
chore/security-dependency-update

Conversation

@samgbafa

@samgbafa samgbafa commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Updates dependencies for open Dependabot alerts on the root Cargo.lock, and migrates the S3 storage backend from aws-sdk-s3 0.19 to 1.x (the only way to leave aws-smithy-json 0.49 and webpki 0.21.4). Toolchain pin is rust-toolchain.toml 1.97.1; no rust-version/MSRV is declared in the workspace.

Fixed (root Cargo.lock, shipped)

Alert Severity GHSA Crate From → To
#165, #63 high GHSA-4w2j-m93h-cj5j, GHSA-6xvm-j4wr-6v98 quinn-proto 0.11.13 → 0.11.15
#93, #87, #85, #81, #80 high GHSA-xp3w-r5p5-63rr, GHSA-pqf5-4pqq-29f5, GHSA-8c75-8mhr-p7r9, GHSA-hppc-g8h3-xhp3, GHSA-ghm9-cr32-g9qj openssl 0.10.75 → 0.10.80 (openssl-sys 0.9.117)
#90 (0.103 line only) high GHSA-82j2-j2ch-gfr8 rustls-webpki 0.103.9 → 0.103.15; see Not fixed for 0.101.7
#170 high GHSA-8ffr-xgwf-xj56 aws-smithy-json 0.49.0 → 0.62.7
#5 high GHSA-8qv2-5vq6-g2g7 webpki 0.21.4 → removed (aws-sdk 0.19 chain)
#173 medium GHSA-2mjx-qc3c-rqvc rustls 0.23.36 → 0.23.45
#69 medium GHSA-pwjx-qhcg-rvj4 rustls-webpki 0.103.9 → 0.103.15
#167 medium GHSA-7gcf-g7xr-8hxj serde_with 3.16.1 → 3.21.0
#98, #65, #64 medium GHSA-3pv8-6f4r-ffg2, GHSA-gchp-q4r4-x4ff, GHSA-j4xf-2g29-59ph tar 0.4.44 → 0.4.46
#97, #95 medium GHSA-phqj-4mhp-q6mq, GHSA-xv59-967r-8726 openssl → 0.10.80
#86 low GHSA-xmgf-hq76-4vx2 openssl → 0.10.80
#57 medium GHSA-r6v5-fh4h-64xc time 0.3.45 → 0.3.47
#54 medium GHSA-434x-w66g-qw3r bytes 1.11.0 → 1.11.1
#89, #77 low GHSA-cq8v-f236-94qc rand 0.8.5 → 0.8.6, 0.9.2 → 0.9.3
#58 low GHSA-3288-p39f-rqpv keccak 0.1.5 → 0.1.6
#62, #61, #51, #50, #49, #48 low GHSA-g59m-gf8j-gjf5 aws-sdk-s3 / -sts / -sso / -dynamodb 0.19 → 1.x; aws-sdk-dynamodb was unused and is removed
#47 low GHSA-rhfx-m35p-ff5j lru resolved at 0.16.4 via the new SDK graph; 0.12.5 remains from another dependent
#46 low GHSA-9c48-w39g-hm26 rsa see note below

The ring 0.16 / rustls 0.19 / sct / untrusted 0.7 chain is also gone (it came from aws-sdk 0.19). ring 0.17.14 is unchanged.

Code change (tinycloud-node-server/src/storage/s3.rs, tests/at_rest_harness.rs): SDK 1.x API port. Behaviour notes:

  • S3 client sets request_checksum_calculation/response_checksum_validation to WhenRequired (SDK 1.x defaults add CRC32 trailers, aws-chunked uploads and checksum-mode GETs, which the 0.19 SDK did not send and some S3-compatible providers reject). BehaviorVersion is pinned to v2026_01_12 instead of latest().
  • Custom endpoint now uses endpoint_url + force_path_style(true) (the old immutable endpoint was path-style).
  • The SDK's default HTTPS client pulls in rustls with aws-lc-rs. Next to the existing ring provider this leaves rustls with no unambiguous default CryptoProvider (the egress/hooks tests panicked). The SDK is built with default-features = false and an explicit aws-smithy-http-client on rustls-ring (s3::http_client()), so aws-lc-rs is not in the build.
  • S3StoreError::S3 is boxed (clippy result_large_err).
  • test/m1-realdata-e2e and test/w5-policy-runtime-node-e2e lockfiles refreshed (CI runs them --locked and they depend on tinycloud-node); metadata --locked passes for both.

Not fixed (root Cargo.lock)

Deferred: test-fixture only, can wait

  • test/m1-realdata-e2e/Cargo.lock: 34 alerts (partially refreshed here for the SDK change)
  • test/w5-policy-runtime-node-e2e/Cargo.lock: 32 (same)
  • test/load/signer/Cargo.lock: 22 (untouched)
    These are not in the node binary or Docker image.

Security-sensitive bumps (for review)

rustls 0.23.36 → 0.23.45; rustls-webpki 0.103.9 → 0.103.15; openssl 0.10.75 → 0.10.80; keccak 0.1.6; rand 0.8.6 / 0.9.3; new aws-sigv4 1.6.0 (SigV4 signing for S3) and sha2/hmac/digest 0.11/0.13 (aws-lc-free SDK graph); ring 0.16 and webpki 0.21 removed.

Verification

Local, Rust 1.97.1: cargo fmt --check, RUSTFLAGS=-Dwarnings cargo clippy --workspace --all-targets, cargo test --workspace against a local PostgreSQL 14 (no Docker access), duckdb test commands from CI, wasm32 build of sdk-wasm/verifier-wasm: pass. Not run locally: Docker build; postgres_space_filter_survives_a_collation_that_ignores_the_sentinel (needs PG16 ICU rules); blackhole_* pool-timeout tests (iptables); at-rest MinIO harness, M1/W5 e2e. CI will cover these.

@samgbafa samgbafa left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES

Reviewed at 4bf41de20834592fff0273ee800ad3b5842801e6. One blocking finding (1): the S3 client runs the SDK 1.x checksum defaults. Everything else is non-blocking or confirmed.

Findings

  1. Medium, blocking. Checksum defaults change the wire format. tinycloud-node-server/src/storage/s3.rs:73-86 (new_client) sets neither request_checksum_calculation nor response_checksum_validation, so aws-sdk-s3 1.129 uses WhenSupported for both. 0.19 sent no checksums and validated none. I pointed the ported client at a loopback S3 stub and recorded what it sent:

    • PutObject with an in-memory body (MemoryStaging) adds x-amz-sdk-checksum-algorithm: CRC32 and x-amz-checksum-crc32.
    • PutObject with ByteStream::from_path (the TempFileSystemStage path, s3.rs:391-396 and :433-438) switches to content-encoding: aws-chunked, x-amz-content-sha256: STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER and an x-amz-trailer checksum. That's a different upload encoding, not just an extra header, and several S3-compatible providers and older MinIO releases reject it.
    • GetObject sends x-amz-checksum-mode: ENABLED. When the stub returned a wrong x-amz-checksum-crc32, read() streamed all of the body and then failed with streaming error at EOF. So a mismatch aborts a response that is already partly sent; it doesn't reject the read up front.

    Ruling: the proposed fix is required. Set RequestChecksumCalculation::WhenRequired and ResponseChecksumValidation::WhenRequired on the S3 config builder in new_client. That restores the 0.19 behaviour, because PutObject, GetObject, HeadObject, DeleteObject and ListObjectsV2 don't require checksums. The endpoint is configured by the operator, and dev/CI run against MinIO, so the port shouldn't depend on which provider is behind it. Mirroring the setting in the harness client (tests/at_rest_harness.rs:142-160) is optional but keeps it consistent. After the push, the same probe should show no x-amz-checksum-* headers, no aws-chunked and no x-amz-checksum-mode.

  2. Low, non-blocking: alerts the description claims as fixed stay open. rustls-webpki 0.101.7 (Cargo.lock:7622) and rustls 0.21.12 are still in the node graph, through rocket_http 0.5.1 and reqwest 0.11.27, which comes from ssi did-web/did-ion/did-tz. Alerts #73 and #74 (>=0.101.0, <0.103.12) and #90 (<0.103.13) cover 0.101.7, so they won't close. Please move them to "Not fixed". #90 is a panic while parsing a CRL; I found no CRL configuration in the node, core or the vendored sqlx (inference: no reachable path).

  3. Low, non-blocking: BehaviorVersion::latest() (s3.rs:34, harness :142) together with the behavior-version-latest features (Cargo.toml:27-28). A future lockfile refresh can change SDK defaults without any change to the code. Consider pinning BehaviorVersion::v2026_01_12().

  4. Info: timeouts and retries. 0.49 configured no timeouts ("If no timeout is specified, requests will never time out"); its retry was standard with 3 attempts. 1.x with this behaviour version has a 3.1 s connect timeout, no operation timeout, standard retry with 3 attempts, and stalled-stream protection on uploads and downloads (20 s grace). The stall detector doesn't count time when the consumer isn't polling, so slow downstream clients are fine. These bound the time a request can hang, and I'd accept them as they are. Retrying PutObject is safe because keys are content-addressed.

  5. Info: credential chain unchanged. aws_config::defaults uses the same order as 0.49 from_env: env, then profile/SSO/credential_process, web identity, ECS, IMDS. docker-compose.dstack-postgres.yaml:37-39 sets static AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_DEFAULT_REGION, so the env provider wins. IMDS is reached only if those are empty, as before. Optional hardening: add AWS_EC2_METADATA_DISABLED=true to the compose (tests/s3_block_store.rs:31 already does this).

  6. Info: region, endpoint and path style are correct. The 1.x region chain still reads AWS_DEFAULT_REGION after AWS_REGION. The production compose always sets TINYCLOUD_STORAGE_BLOCKS_ENDPOINT (:36, from the S3_ENDPOINT secret), so force_path_style(true) always applies there. The probe confirmed requests go to /<bucket>/<key>, and the trailing / that Uri::to_string adds is handled. SDK 0.19 had no virtual-host addressing, so this matches the old behaviour. AWS S3, MinIO and R2 all accept path style. The compose and env names are AWS-style and don't identify the provider; earlier infrastructure analysis found production is not R2 and is most likely AWS S3. A config without an endpoint now gets virtual-host style; that only matters off production.

  7. Info: error mapping is equivalent. HeadObject NotFound returns None/false, GetObject NoSuchKey returns None, and InvalidRange goes through HeadObject to Unsatisfiable. A missing Content-Length becomes 0, the same as 0.19's default. No caller matches the boxed S3StoreError::S3. S3 errors are outside the TC-1054 retryable/outcome-unknown classification, which covers database errors only (routes/mod.rs:160-190), both before and after this PR, so nothing regresses there. Multipart isn't used. The range-read path is ported as it was.

  8. Confirmed: TLS. cargo tree -i aws-lc-rs and -i aws-lc-sys find nothing, with default features, --all-features, --all-features --target all and --workspace. webpki and ring 0.16 are gone. rustls 0.23.45 has only the ring provider feature. The S3 client builds on an explicit ring provider (s3.rs:25-31), and Postgres TLS (the vendored sqlx _tls-rustls-ring-*) and the link proxy use ring explicitly. The root store hasn't changed: native roots before (hyper-rustls 0.22 with_native_roots) and after (rustls-native-certs 0.8), and the image copies ca-certificates.crt. The egress and hook lib tests ran without a CryptoProvider panic.

  9. Confirmed: other crypto bumps are patch-level. The node's direct hmac 0.12/sha2 0.10 are unchanged. sha2 0.11 and hmac 0.13 are used only by aws-sigv4 1.6 and aws-smithy-checksums. keccak 0.1.6 reaches SIWE/CACAO through sha3; the siwe, cacaos and siwe-recap tests pass (17). openssl 0.10.80 is reached only through native-tls in reqwest 0.11 (DID resolution). No source changes were needed outside the S3 port.

  10. Confirmed: deferrals. alloy-dyn-abi is in Cargo.lock:189 but isn't compiled: cargo tree -e features -i alloy-dyn-abi is empty for tinycloud-node with default features and with --all-features. The m1/w5 lock refreshes only touch test crates.

Local verification (no Docker)

cargo build passes. Storage lib tests pass (3/3). at_rest_harness non-ignored tests pass (11). s3_block_store compiles; its one test is ignored because it needs MinIO. The siwe/cacao tests pass. The egress/hook lib tests: 79 pass, and the 2 that fail need TINYCLOUD_TEST_POSTGRES_URL, which wasn't set (environment, not this PR).

Must be green before merge (after the fix in 1)

  • Docker image build (alpine/musl, ring via aws-smithy-http-client).
  • at-rest harness (native PostgreSQL + MinIO): the green checks, plus s3_block_store -- --ignored against MinIO (PUT/GET/HEAD/DELETE/LIST, path style, SigV4 1.6 signing).
  • M1 real-data and W5 policy-runtime e2e jobs (--locked).
  • Full workspace tests with PostgreSQL.

No CI job covers the production bucket (signing and region against the real endpoint). Run a KV put/get smoke right after the first deploy.

@samgbafa samgbafa left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE (delta from 4bf41de)

Reviewed at f9dd41eacf29ba60bdae97b866dd42da37ae21f7. Finding 1 from the previous review is resolved, and findings 2 and 3 are addressed.

Scope of the delta

One commit. It touches only tinycloud-node-server/src/storage/s3.rs, tinycloud-node-server/tests/at_rest_harness.rs and tinycloud-node-server/Cargo.toml, where the behavior-version-latest features are dropped. Cargo.lock is unchanged. cargo tree -i aws-lc-rs is still empty with --all-features --target all.

Checksum behaviour (re-ran the loopback S3 stub probe)

  • PutObject, in-memory body (through persist with MemoryStaging): sends x-amz-content-sha256: <hex> and a plain body. No x-amz-checksum-* and no x-amz-sdk-checksum-algorithm.
  • PutObject, ByteStream::from_path: sends content-length: 9, x-amz-content-sha256: UNSIGNED-PAYLOAD and a raw body. No aws-chunked, no STREAMING-*-TRAILER and no x-amz-trailer.
  • GetObject: no x-amz-checksum-mode. The stub's deliberately wrong x-amz-checksum-crc32 is ignored and the body reads in full (11 bytes), as with 0.19.
  • ListObjectsV2 and HeadObject: no checksum headers. Requests stay path-style (/<bucket>/<key>).

WhenRequired is set on the S3 config builder after Builder::from(&sdk_config), so it overrides any value taken from shared config or environment. The harness client mirrors it.

Other items

  • Behaviour version: BehaviorVersion is pinned to v2026_01_12 through s3::behavior_version(), and the harness uses the same function. Resolves finding 3.
  • PR description: it now lists rustls-webpki 0.101.7 (via rocket_http and reqwest 0.11) as not fixed, with #90, #73 and #74 still open. Resolves finding 2.

Local verification (no Docker)

  • cargo build passes.
  • Storage lib tests pass (3/3).
  • at_rest_harness non-ignored tests pass (11).
  • s3_block_store compiles; its one test is ignored because it needs MinIO.

Merge prerequisites

  • CI green:
    • Docker image build;
    • at-rest harness (native PostgreSQL + MinIO), including s3_block_store -- --ignored;
    • M1 real-data and W5 policy-runtime e2e jobs;
    • full workspace tests with PostgreSQL.
  • After the first deploy, run a KV put/get smoke against the real production bucket. No CI job covers signing, region or endpoint against it.

@samgbafa

Copy link
Copy Markdown
Contributor Author

APPROVE (delta review at exact head 5634de6). The approved change set from f9dd41e is carried forward byte-identical: this delta is a merge of main (9a2e453) plus one lockfile line.

Delta f9dd41e..5634de6:

  • This PR's own changes are unchanged: storage/s3.rs and the at-rest harness have no diff. In tinycloud-node-server/Cargo.toml the only changes come from main (version 1.21.3; ed25519-dalek moved from dev-dependencies to dependencies for the issuer-set canonical-point check). The aws-config, aws-sdk-s3 and aws-smithy-http-client lines are untouched.
  • The merge was automatic, with no conflicts resolved by hand.
  • The follow-up commit updates one line in test/w5-policy-runtime-node-e2e/Cargo.lock (tinycloud-node 1.21.2→1.21.3) so --locked passes.
  • Security-relevant versions in the root lockfile are unchanged: rustls 0.23.45, rustls-webpki 0.103.15, openssl 0.10.80, quinn-proto 0.11.15, aws-sdk-s3 1.129.0; there is no aws-lc-rs.

Merge prerequisites stand: a fresh green CI at this head (Docker build, MinIO at-rest harness + s3_block_store --ignored, m1/w5, full PostgreSQL workspace), then a KV put/get smoke against the real bucket after the first deploy.

@samgbafa
samgbafa merged commit 9754286 into main Oct 19, 2026
22 checks passed
@samgbafa samgbafa mentioned this pull request Oct 19, 2026
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