paritytech / paritytech/web3-storage
Comprehensive codebase audit: security, performance, code quality, and CI gaps
@RafalMirowski1 is already working on this.
Since Jun 10, 2026.
- Dominant language
- Rust
- Stars
- 13
- Forks
- 3
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 33
Description
Comprehensive Codebase Audit
Full audit of the dev branch covering security, performance, code quality, TODOs, and CI/config gaps. Findings are grouped by severity across 5 categories.
Critical (8 items)
Security
S1. Missing signature verification in delete_data endpoint
-
provider-node/src/api.rs:456-478 - The
admin_signaturefield is accepted but explicitly ignored (let _ = request.admin_signature). Any user can delete arbitrary bucket data without authentication. - Fix: Verify signature using the auth module before allowing deletion.
S2. Permissive CORS configuration
-
provider-node/src/api.rs:80 -
CorsLayer::permissive()allows requests from any origin. Combined with S1, this creates a remotely-exploitable attack vector. - Fix: Restrict to trusted origins or make configurable.
Performance
P1. Unbounded iteration in on_finalize hook
-
pallet/src/lib.rs:62-74 - Iterates over all expired challenges for a block without bounds. An attacker can create many challenges expiring at the same block, stalling the chain. The
index as u16cast also silently truncates at 65536. - Fix: Cap processing per block (e.g., 100), carry remainder to next block.
CI / Config
C1. Missing try-runtime feature in pallet-drive-registry
-
storage-interfaces/file-system/pallet-registry/Cargo.toml - Pallet doesn't declare the
try-runtimefeature block. Will breakzepter run checkfeature propagation lint. - Fix: Add
try-runtimefeature with proper propagation.
C2. Missing try-runtime feature in pallet-s3-registry
-
storage-interfaces/s3/pallet-s3-registry/Cargo.toml - Same issue as C1.
TODOs blocking functionality
T1. Checkpoint duty query returns empty vec
-
provider-node/src/checkpoint_coordinator.rs:329 -
get_active_checkpoint_duties()has a TODO and returnsOk(vec![]). Provider-initiated checkpoints are non-functional.
T2. Challenge detection returns empty vec
-
provider-node/src/challenge_responder.rs:304 - Challenge storage query is unimplemented, relies on event detection which is also incomplete.
T3. no-admin-left scenario unhandled in agreement removal
-
pallet/src/lib.rs:1563 -
TODO(no-admin-left)— when removing the last primary provider from a bucket, no admin safeguard exists.
High (14 items)
Security
S3. Path traversal in file-system API
-
provider-node/src/fs_api.rs:59-61 - Path validation only checks for leading
/. Paths like/../../../etc/passwdare not blocked. - Fix: Reject paths containing
.., normalize components.
S4. Unbounded storage iteration in complete_deregister
-
pallet/src/lib.rs:~1028-1040 -
CheckpointRewards::<T>::iter_prefix(&who).collect()is unbounded. A provider with thousands of reward entries can DoS the extrinsic. - Fix: Paginated draining or limit bucket participation.
S5. Block number truncation to u32
-
pallet/src/lib.rs:3794 -
current_block.try_into().unwrap_or(0u32)silently masks overflow. Historical root tracking becomes incorrect on chains with BlockNumber > 2^32. - Fix: Use
saturated_into::<u64>()or return error.
S6. Unchecked division in slashing calculations
-
pallet/src/lib.rs:3047, 3850, 2683 -
challenge.deposit * challenger_percent / 100andactual_penalty / 10use unchecked arithmetic on Balance types. - Fix: Use
checked_mul/checked_divwith explicit error.
Performance
P2. O(n) provider search in find_matching_provider
-
pallet/src/lib.rs:3450-3507 - Full linear scan of all providers for every auto-match request. At 1000+ providers this is expensive.
- Fix: Add secondary indexes (
ProvidersAcceptingPrimary,ProvidersByPriceRange).
P3. Unbounded Challenges storage
-
pallet/src/lib.rs:197-202 -
#[pallet::unbounded]with no pruning. Challenges accumulate faster than settlement. - Fix: Auto-prune challenges older than configurable age.
P4. O(n²) nested loop in checkpoint signature verification
-
pallet/src/lib.rs:2293-2310, 2382-2407 - For each signature, does
primary_providers.iter().position()— O(n) inner search. - Fix: Build a HashMap of provider→index before the loop.
P5. Repeated sequential storage reads
-
pallet/src/lib.rs:1945-1954, 2610-2645 - Multiple
::get()calls for agreement, bucket, and provider info that could be loaded together. - Fix: Batch reads upfront.
Code Quality
Q1. Silent error swallowing across provider-node
-
provider-node/src/replica_sync_coordinator.rs:325, 703— channel send and event results discarded -
provider-node/src/api.rs:461— admin_signature unused -
provider-node/src/challenge_responder.rs:298, 511— storage/event results discarded -
provider-node/src/fs_api.rs:67— bucket init failures ignored -
provider-node/src/storage/mod.rs:276— MMR node storage failures ignored - Fix: Log warnings for non-critical, propagate errors for critical.
Q2. unwrap() in production HTTP handlers
-
provider-node/src/fs_api.rs:164,171,provider-node/src/s3_api.rs:164-248,provider-node/src/api.rs:639 - Header parsing and bucket access use
unwrap()/.parse().unwrap(). - Fix: Use proper defaults without panicking.
Q3. Missing runtime migrations for new storage items
-
pallet/src/lib.rs -
CheckpointConfigs,CheckpointRewards,MemberBucketsstorage items have noon_runtime_upgrade()hooks. - Fix: Add migration code before any mainnet/testnet upgrade.
CI
C3. No security audit in CI
- No
cargo audit, no secret scanning, no SAST in any workflow. - Fix: Add
cargo audit --deny warnings+ secret scanning job.
C4. Missing precompile unit tests in CI
-
.github/workflows/check.yml -
pallet-storage-provider-precompile,pallet-drive-registry-precompile,pallet-s3-registry-precompilehave no dedicated test job. - Fix: Add
cargo test -p <precompile>to CI.
C5. No try-runtime test coverage in CI
-
.github/workflows/check.yml - Builds with
try-runtimefeature but never runs tests with it. Migration bugs won't surface until live. - Fix: Add
cargo test --workspace --features try-runtime.
Medium (16 items)
Security
S7. Unvalidated max_keys in S3 list objects
-
provider-node/src/s3_api.rs:293 - Defaults to 1000 with no upper bound. Client can request millions.
- Fix:
std::cmp::min(max_keys, 10_000).
S8. Integer overflow in challenge index as u16
-
pallet/src/lib.rs:69 - >65535 challenges per deadline causes ID collisions.
- Fix: Use u32 or enforce limit.
S9. Insufficient public key validation
-
pallet/src/lib.rs:878-883 - Only checks length (32/33/64), not actual key validity.
Performance
P6. No per-connection rate limiting
-
provider-node/src/api.rs:78 - 256 MB body limit with no streaming/rate limiting per connection.
P7. Missing request-level timeouts in replica sync
-
provider-node/src/replica_sync.rs:45-51 - HTTP requests have no individual timeout.
P8. Unbounded membership cache growth
-
provider-node/src/auth.rs:50-104 -
DashMap<u64, CachedMembership>has no size limit or LRU eviction.
P9. Vec allocation without capacity
-
provider-node/src/api.rs:523 -
Vec::new()then push in loop. UseVec::with_capacity(request.hashes.len()).
P10. Sequential RocksDB deserialization on every stats() call
-
provider-node/src/storage/disk.rs:128-150 -
iter_buckets()deserializes all bucket states on every call. - Fix: Cache stats summary, update incrementally.
Code Quality
Q4. Missing rustdoc on public APIs
-
client/src/checkpoint.rs—ProviderHealthHistory,CheckpointManager,CommitmentCollectionmethods -
client/src/base.rs—ClientErrormissing Timeout/SignatureVerification/Crypto variants
Q5. Hardcoded magic numbers
-
provider-node/src/replica_sync_coordinator.rs:37-46— poll interval 12s, timeout 300s, max concurrent 3 -
client/src/checkpoint.rs:70— consensus threshold 51% - Fix: Move to config file or environment.
Q6. Incomplete upload_replicated() stub
-
client/src/storage_user.rs:115-138 - API exists but logs "Would replicate" without doing anything. Misleads users.
- Fix: Either implement or mark
#[doc(hidden)]/ remove.
Q7. String-based account IDs instead of typed
-
client/src/discovery.rs:68,client/src/admin.rs:21 -
pub account: Stringinstead ofAccountId32. SS58 prefix mismatch causes comparison bugs.
Q8. Inconsistent error handling patterns
- Mix of structured errors (
Error::InvalidHash), string errors (#[error("Node not found: {0}")]), and silently discarded results across modules.
CI / Config
C6. Layer 1 unit tests missing from main CI
-
file-system-primitives,s3-primitives,pallet-drive-registry,pallet-s3-registryonly tested via integration tests. - Fix: Add
cargo test -p <crate>to check workflow.
C7. serde_json default-features inconsistency
- Workspace
Cargo.toml:133declaresdefault-features = false, butruntime/Cargo.tomloverrides withdefault-features = true.
C8. Hardcoded port assumptions
-
justfile:22-30— ports 9900, 2222, 3333 hardcoded with no conflict detection.
Low (10 items)
Performance
- P11. No graceful shutdown handler in provider node (
provider-node/src/command.rs:119-125) - P12. Weight accuracy for provider_checkpoint may drift (
pallet/src/weights.rs:500-510) - P13. No retry/backoff logic in checkpoint/replica sync coordinators
Code Quality
- Q9.
expect()in genesis config (pallet/src/lib.rs:273) — chain fails to boot with cryptic panic - Q10. Content-defined chunking documented but unimplemented (
client/src/base.rs:213-223) - Q11. S3
list_objectspagination unimplemented (storage-interfaces/s3/client/src/substrate.rs:457) - Q12. HTTP header parsing uses nested
unwrap()fallbacks that hide bad input (provider-node/src/s3_api.rs:164-172) - Q13. Duplicated HTTP header parsing logic between
fs_api.rsands3_api.rs - Q14. Mixed builder patterns —
with_dev_signer(self)vsset_dev_signer(&mut self)(client/src/base.rs:120-151)
CI / Config
- C9.
scripts/runtimes-matrix.jsonhas"TODO: update WSS"placeholders (lines 9, 28) - C10. Single zombienet collator doesn't test multi-collator consensus scenarios
Summary
| Severity | Security | Performance | Code Quality | CI/Config | TODOs | Total |
|---|---|---|---|---|---|---|
| Critical | 2 | 1 | 0 | 2 | 3 | 8 |
| High | 4 | 4 | 3 | 3 | 0 | 14 |
| Medium | 3 | 5 | 5 | 3 | 0 | 16 |
| Low | 0 | 3 | 5 | 2 | 0 | 10 |
| Total | 9 | 13 | 13 | 10 | 3 | 48 |
Suggested Priority
- Immediate (blocks production safety): S1, S2, P1, S3, S4, T1, T2, T3
- Before testnet upgrade: S5, S6, Q3, C1, C2
- Next sprint: P2-P5, Q1, Q2, C3-C6
- Backlog: Everything else
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.