Corezoid public API uses SHA-1 (non-HMAC) for request signing
medium
CVSS 3.1: 3.9 · Asset: api.corezoid.com + all /api/2/*
- Severity: Medium (compliance + cryptographic hygiene — not immediately exploitable)
- CVSS 3.1:
AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:N→ 3.9 - CWE: CWE-327 (Use of a Broken or Risky Cryptographic Algorithm), CWE-328 (Use of Weak Hash)
- Asset:
api.corezoid.com/api/2/json/{API_LOGIN}/{GMT_UNIXTIME}/{SIGNATURE}and related endpoints (70 paths in OpenAPI spec) - Discovered: 2026-04-26
- Status: Open
Summary
The Corezoid public API signs requests using SHA-1 (not HMAC-SHA256+), with a manual keyed-hash construction rather than a standard HMAC:
// from openapi.corezoid.com documentation
signature = CryptoJS.enc.Hex.stringify(
CryptoJS.SHA1(time + secret + content + secret)
);
This construction has two distinct issues:
Issue A — SHA-1 is cryptographically deprecated
- NIST disallowed SHA-1 for digital signatures in 2013 (SP 800-131A).
- CA/Browser Forum distrusted SHA-1 TLS certs in 2017.
- Practical SHA-1 collisions demonstrated:
- SHAttered (2017) — first practical same-prefix collision, CWI / Google research
- SHA-1 is a Shambles (2020) — first practical chosen-prefix collision, $45K of GPU time
- PCI DSS 4.0, FIPS 186-5, and most banking compliance frameworks prohibit SHA-1 for new deployments.
Issue B — Custom
SHA(k‖m‖k) is not HMAC
HMAC is defined in RFC 2104 with a specific inner/outer padding
construction that protects against length-extension attacks. The
Corezoid pattern SHA1(time + secret + content + secret) is
the "key-then-message-then-key" envelope-MAC, which
provides some protection over the naive SHA1(key + message)
but is:
- Not formally proven secure like HMAC
- Vulnerable to collision-based forgery: if an
attacker can find any two
content_a,content_bwith identical SHA-1 state by the time the second secret is appended, they can forge a valid signature for one given the other - Vulnerable to weaknesses in SHA-1 itself — as SHA-1 collision attacks become cheaper, this scheme degrades faster than HMAC-SHA1 would
Reproduction — confirm the signing scheme
$ curl -sk 'https://openapi.corezoid.com/' | grep -oE 'signature\s*=\s*CryptoJS[^<]{0,200}'
signature = CryptoJS.enc.Hex.stringify(CryptoJS.SHA1(time + secret + content + secret));
Also visible in Postman collection examples and the
docs/corezoid-api.json spec (70 paths, all using
{SIGNATURE} path parameter).
Impact
Direct exploitation is difficult today — SHA-1
collisions cost money and time, and targeted collisions on
time + secret + content + secret are harder still because
the attacker doesn't know secret. The realistic attack
scenarios are:
- Compliance failure. PCI DSS 4.0 (effective 2025), HIPAA, EU NIS2 for critical infrastructure, and many banking regulators explicitly require SHA-2 family hashes for new implementations. For any Corezoid customer in a regulated industry, SHA-1 signing is an audit blocker.
- Collision attack becomes cheaper over time. In 2017, a full SHA-1 collision cost ~$110K of GPU time. By 2020 it was 45K(chosen − prefix).By2026withconsumerGPUsandcloudcompute, chosen − prefixSHA − 1collisionsareplausibly<10K — still not trivial for internet-random attackers, but affordable for motivated adversaries.
- Key-material leakage amplifies risk. If the API secret for a single customer leaks (via log exposure, HAR capture, CI dump, etc.), an attacker who captured historical request/response pairs can verify their stolen secret works — and SHA-1's structural weaknesses give them additional signature-forgery options that HMAC-SHA256 would close off.
- Downgrade scenario. If Corezoid ever ships a client library that accepts "SHA1 OR SHA256 signatures" during a migration, attackers can force-downgrade by omitting the algorithm-identifier header.
Remediation
Priority 1 — add SHA-256 as primary, keep SHA-1 for backward compat:
- Introduce HMAC-SHA256 as the preferred signature:
signature = HMAC-SHA256(key = secret, message = time + content).hex() - Accept both SHA-1 and HMAC-SHA256 signatures during migration, but
add a header (e.g.,
X-Signature-Version: 2) so the server knows which is being used. Without an explicit version header, reject the request. - Warn customers via API response header:
Deprecation: version="1.0", sunset=2027-01-01when a SHA-1 signature is used. - Publish a migration guide.
Priority 2 — enforce HMAC-SHA256 only:
- After 6-12 months of dual-acceptance + deprecation warnings, disable SHA-1 signatures entirely.
- Update client SDKs, Postman collections,
openapi.corezoid.comdocs,corezoid-ai-docrepo.
Priority 3 — strengthen the construction:
- Use standard HMAC (RFC 2104), not envelope-MAC. HMAC-SHA256 output should be the hex representation of the full 32-byte digest.
- Include the full HTTP method, URL path, query string, and request body in the signed content — otherwise an attacker who captures a valid signature can replay it against different endpoints (partial-URL replay attack).
- Tighten the
GMT_UNIXTIMEfreshness window to ±60 seconds (common: ±5 minutes is common but excessive). - Include a nonce in the signed content to prevent replay within the freshness window.
Context — what's working well
- The three-part URL (
/API_LOGIN/GMT_UNIXTIME/SIGNATURE) design is reasonable — time-based freshness + identity + MAC - The OpenAPI spec versioning and documentation quality is good
- Using secret on BOTH ends of the hash (rather than just prefix) already provides some length-extension protection — just not as much as HMAC