| Deliverable | Status | Evidence |
|---|---|---|
| Mainnet contract deployment | DONE | Package + 6 shared objects, all verified on chain — §5 |
| Contract test suite | DONE | 124 Move tests passing — §3 |
| Security review + remediation | DONE | 10 defects found and fixed, each with a test — §4 |
| Dependency security scan | DONE | Production high-severity: 14 → 0 — §4.3 |
| Monitoring & alerting | DONE | 27 engine metrics, 11 alert rules, Grafana dashboards live — §6 |
| Health endpoint | DONE | Per-component checks with a documented status contract; verified live — §6 |
| Status page | DONE | Backed by the health endpoint above — §6 |
| QA checklist / beta testing guide | DONE | 221 documented cases, published to testers — §3.3 |
| Load & stress testing | IN PROGRESS | 5 k6 scripts written; two runs completed, both invalidated — §3.4 |
| Demo video | PENDING | §2 |
| Module | Coverage | What it proves |
|---|---|---|
124 tests passing, 0 failing. Reproduce with
sui move test in waldrop-contracts.
|
||
storage |
blob registry, ACL, folders | Includes the SEAL access path: a folder viewer can decrypt files in that folder and not in another; moving a file in or out grants and revokes immediately |
subscription |
plans, billing, upgrades | Tier limits, payment, downgrade and renewal lifecycle |
admin |
config, pause, capability | AdminCap gating and the emergency pause switch |
treasury |
fees, refunds | Withdrawal and pro-rated refund arithmetic |
migration |
job lifecycle | Declared-vs-verified ceilings, quota refunds on release |
Six executable suites in waldrop_app/scripts/. Each exists
because a specific defect was found; the tests are the regression guard,
not coverage theatre.
| Suite | Cases | Guards against |
|---|---|---|
safe-redirect-test |
20 |
Open redirect via //evil.com and backslash
normalisation
|
preview-diff-test |
21 | AI preview showing a misleading diff (row-count mismatch, column reorder) |
rate-limit-test |
21 |
Reading the wrong end of x-forwarded-for, which
silently disables the limiter
|
walrus-endpoint-test |
18 | SSRF via caller-supplied publisher/aggregator override |
capped-stream-test |
11 | Byte cap being advisory rather than enforced mid-stream |
bcs-schema-test |
2 schemas | BCS drift against the Move source — the failure mode that produced defect D-9 below |
221 documented cases across 12 sections, published to
beta testers at testing.waldrop.xyz. Prioritised P0/P1/P2,
with a bug-report template that requires /api/health output
— so a dependency outage is never filed as a product defect.
| Section | Cases |
|---|---|
| First run — sign-in, funding, plan, first upload | 29 |
| Source connectors (local, URL, S3, GCS, Azure, SFTP, Drive, Dropbox) | 68 |
| Upload configuration | 16 |
| Transform pipeline | 50 |
| Folders + folder sharing | 34 |
| Error handling, cross-browser, responsive | 13 |
| Morse (AI) — incl. a privacy canary test | 11 |
Five k6 scripts, one per tier of the stack, so a run identifies which layer degraded rather than only that something did: publisher, aggregator, engine, backend API, frontend.
Run 1 reported a 97% error rate. Diagnosis: the scripts sent deliberately invalid input (a placeholder blob id, an auth request with no wallet address). The API correctly rejected all of it; k6 counted correct rejections as failures. A harness defect, not a product defect.
Run 2, after fixing the inputs, reported 56%. Cause:
403 challenge responses from Vercel's DDoS mitigation —
30 virtual users from one IP is what an attack looks like.
This is itself evidence for the DDoS-protection requirement: a single-source flood was detected and challenged at the edge. But it means neither run produced valid capacity numbers, so neither is presented as one.
Valid latency data was captured from run 2, since those requests did complete: p95 of 936–973 ms across seal, walrus-read, auth and health under 60 concurrent users, with the health endpoint inside its 1500 ms budget.
Single-client sequential measurements — a latency floor, not a capacity figure. Taken from outside AWS across a cross-Pacific hop to the ap-northeast-1 publisher, so these are an upper bound on what a co-located client would see.
| Endpoint | Median | p90 | Max | Reading |
|---|---|---|---|---|
| Walrus aggregator — blob read | 699 ms | 768 ms | 2679 ms | Tight median; the outlier is the number to watch under load |
Walrus publisher — /v1/api |
949 ms | 1086 ms | 2186 ms | Liveness probe, not an upload |
App /api/health — all 4 components |
engine 192 ms · publisher 481 ms · aggregator 465 ms · Sui RPC 100 ms | Parallel checks, so total ≈ the slowest, not the sum | ||
The 2.2–2.7 s maxima against a sub-second median are the finding here: variance rather than latency. Both are consistent with the publisher sitting in ap-northeast-1 while application traffic originates in us-east-1 — a planned relocation, tracked in §7.
Ten defects were found during review and remediated. Each is listed with how it would have presented to a user, because severity is easier to judge from the symptom than from the cause.
| ID | Defect | Severity | How it would have presented |
|---|---|---|---|
| D-1 | Open redirect in all four OAuth callbacks | HIGH |
After a successful Dropbox/Drive sign-in, a crafted
returnTo sent the user off-origin —
//evil.com and /\evil.com both passed
the old guard
|
| D-2 | SSRF in the Walrus proxy | HIGH |
A caller-supplied ?publisher= received a
server-minted, signed upload credential
|
| D-3 | Credential leak in the SEAL proxy | HIGH |
cookie, authorization and
x-api-key forwarded upstream unstripped
|
| D-4 | Unauthenticated cloud-connector routes | HIGH | All five connectors fetched remote data with no session check |
| D-5 | Unbounded download size | MEDIUM | A connector source could stream unlimited bytes into the server |
| D-6 |
xlsx@0.18.5 — unpatched prototype-pollution CVE
|
HIGH | Attacker-supplied spreadsheets parsed by a package abandoned on npm since 2022, with no fix available. Removed entirely rather than pinned — the engine already reads xlsx natively |
| D-7 | AI credit checked after profiling | MEDIUM | A user with zero AI quota could still force the engine to read and scan an entire file, unmetered |
| D-8 | No rate limiting on AI routes | MEDIUM | Model spend exposed to a single abusive client |
| D-9 | BCS schema two fields behind the contract | HIGH | Every user's file list silently empty, with no error anywhere. BCS is positional, so a short schema does not throw — it misreads bytes. Five hand-maintained copies existed; consolidated to one, with a test that diffs it against the Move source |
| D-10 | Billing period counted in the wrong epoch clock | MEDIUM |
The contract counts in Sui epochs (~24 h) and Walrus epochs (14
days). A comment claimed billing used Walrus epochs; the shipped
default of 2 produced a
two-day subscription
|
| Scope | Before | After | Notes |
|---|---|---|---|
| Production, high severity | 14 | 0 | next 16.1.6 → 16.3.0 cleared 30 advisories |
| Production, moderate | 13 | 0 | |
| Transitive, unreachable | — | 2 |
nanoid (needs a custom generator with size 0) and
uuid (needs v3/v5/v6 with a caller buffer). Neither
code path is used — documented rather than force-upgraded
|
| Dev-only tooling | — | 4 |
eslint, shadcn transitives; never
shipped
|
| Control | Implementation |
|---|---|
| SEAL decryption gate |
seal_approve binds the SEAL id to the store's object
id and reads the marker from the id rather than trusting the
caller — so a viewer cannot decrypt blob B while claiming access
to blob A
|
| SEAL marker uniqueness | Enforced on registration. Without it, a second blob sharing a marker would silently repoint the first blob's folder access |
| Account transfer | Refuses while any share survives; store viewers, per-blob shares and folder shares must all be cleared first, so no grant crosses a handover |
| Emergency pause | Blocks every operation that grants access, including moving a file into an already-shared folder. Revocation is deliberately left working while paused |
| Display metadata |
Gated by &mut Publisher (owned object), the
standard Sui pattern — not by AdminCap. Verified one-shot: a
second call aborts
|
| Admin capability | AdminCap, UpgradeCap, Publisher and DisplayCaps all held on a hardware wallet. Migration to multisig is an open item — §7 |
script-src CSP directive. Adding one
breaks the wallet SDK, Enoki and the Google Picker. This is an accepted
trade with compensating controls — frame-ancestors 'none',
X-Frame-Options: DENY, nosniff, HSTS and a
strict referrer policy are all set and verified served. Recorded so it
reads as a decision rather than an oversight.
Two independent assessments were carried out by The Blockchain Team, both dated 14 August 2026. Full reports:
| Report | Scope | Critical | High | Medium | Low | Info |
|---|---|---|---|---|---|---|
| Move Contracts — Smart Contract Security Assessment |
7 Move modules, 3,720 lines · commit d889b0c · Sui
CLI 1.76.0
|
0 | 3 | 8 | 10 | 6 |
| Waldrop - Security Assessment | 28 API routes, 14 gRPC RPCs, 2,565 LoC of route handlers · white-box, static | 0 | 1 | 4 | 5 | 4 |
d889b0c. The mainnet package 0x2f548bb4… was
published on 12 August — so the audits landed after deployment, and
their findings are not yet reflected on chain. register_blob not checking that the subscription is still
live, where migration::create_job does; and
extend_blob capping the increment rather than the resulting
lifetime. They are recorded in §7 as P0. UpgradeCap is at default policy, so its
holder can publish a version in which seal_approve
approves everyone — retroactively exposing every blob ever encrypted,
because the ciphertext does not change, only the on-chain predicate
guarding the key.
| Object | Id |
|---|---|
| Package |
0x2f548bb4bb1e5f7622c527417d3c0221840d0412ec23d70306f1bd4b79c20b45
|
| GlobalConfig |
0xd4d4dbb5ae23a8b89a214fd8e0695ba14ced4e8600e6a096169df805cc580b02
|
| PlanRegistry |
0xa560dadd6d3b8acdf5f27a88c62f22efd7c41ae98ffbc0ca3188c8e4b4500936
|
| Treasury |
0x83d23c0e5b71913af2058cdd16f6f57168614d862f16f9481f2679de7c8c8c4b
|
| AdminCap |
0xb7083158b697ff6ff184809d319f14bb101cf37171852763408c0630922d6bdb
|
| UpgradeCap |
0xe30017b431ccb42ea3c05a8437ee876882a6e30c2c51fcd8d340cca4cb6bac0c
|
| Publisher |
0x502a1ca937e47ea94d98d8ea2f96e745e0365a34d19083f1b49fc13f76f0fa2e
|
Self-hosted Walrus publisher and aggregator on AWS behind nginx + TLS, with JWT-authenticated writes. Sui Object Display registered for all five user-facing types, so wallets and explorers render Waldrop objects with names and images rather than raw type strings.
| Component | Status | Detail |
|---|---|---|
| Engine metrics | DONE | 27 Prometheus metrics — throughput, latency histograms, queue depth, memory, error counts by type |
| Per-component health endpoint | DONE |
/api/health checks engine, publisher, aggregator and
Sui RPC independently. 200 ok /
200 degraded / 503 down is the alerting
contract — a non-critical dependency being slow does not page
|
| Alert rules | DONE | 11 rules across availability, saturation and correctness. Every referenced metric verified to exist in source. Error alerts use a ratio, not a count |
| Grafana dashboards | DONE |
Engine dashboard live at monitoring.waldrop.xyz —
throughput, latency percentiles, queue depth, error rate, stage
latency and resource usage
|
| Status page | DONE | Driven by the per-component health endpoint, so each dependency reports separately rather than a single up/down for the whole product |
Stated with cause, not just status. Nothing here is unknown work.
| Item | Priority | Note |
|---|---|---|
| Audit findings H-01, H-02, H-03 | P0 |
Three High-severity resource-metering paths from the contracts
audit (§4.6), each reachable by a single unprivileged user. The
audited commit d889b0c is still HEAD, so
none are fixed and all are live on the deployed package. Fixes
require a redeploy, which abandons existing
BlobStore objects — so sequencing matters
|
| Publisher capacity hardening | P0 |
Root cause identified: no swap, a 512 MB accepted body on a 4 GB
instance, and Restart=on-failure with systemd's
default limit — which gives up after 5 restarts in 10 s, so an OOM
loop leaves the service down permanently. Fix is specified;
re-test follows it, not before
|
| Valid load-test numbers | P0 | Blocked on the above, plus a Vercel bypass token for app-tier runs |
| Demo video | P1 | ≥ 5 minutes |
| Cross-browser / cross-device QA | P1 | Cases documented in the QA guide; execution pending |
| Admin keys to multisig | P1 | AdminCap, UpgradeCap, Publisher and DisplayCaps are on one hardware wallet — a single point of failure |
| Beta plan pricing | P1 | Starter is deliberately 0 USDC during beta and must be set before general availability |
Every number above is reproducible:
# Contract tests
cd waldrop-contracts && sui move test
# Application test suites
cd waldrop_app
for t in safe-redirect preview-diff rate-limit walrus-endpoint capped-stream bcs-schema; do
bun run scripts/$t-test.ts
done
# Dependency scan
bun audit
# Live service health, per component
curl -s https://app.waldrop.xyz/api/health | python3 -m json.tool
# On-chain object verification
sui client object 0x2f548bb4bb1e5f7622c527417d3c0221840d0412ec23d70306f1bd4b79c20b45