Skip to content

Add auth/session crypto primitives and RNG seeding lint - #595

Merged
logbie merged 2 commits into
mainfrom
claude/wfl-crypto-builtins-f3zbrh
Jul 9, 2026
Merged

logbie merged 2 commits into
mainfrom
claude/wfl-crypto-builtins-f3zbrh

Conversation

@logbie

@logbie logbie commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

This change closes three launch-blocking gaps in section 13.1 by adding three new native cryptographic builtins and a static-analysis rule to prevent insecure RNG seeding in security-sensitive code.

Key Changes

New Builtins (src/stdlib/crypto.rs):

  • pbkdf2_hmac_sha256 — Raw PBKDF2-HMAC-SHA256 key derivation with caller-supplied salt, iteration count, and output length. Runs the iteration loop in native Rust to bound per-call cost and prevent DoS on login endpoints. Validated against RFC/NIST standard test vectors.
  • constant_time_equals — Timing-safe string comparison for MACs, CSRF tokens, session IDs, and password-reset codes. Uses the subtle crate to prevent timing-based side-channel attacks.
  • secure_random_bytes — CSPRNG byte generation from the OS, returned as lowercase hex. Provides uniform entropy for salts, session identifiers, and tokens without modulo bias.

Static Analysis Rule (src/analyzer/static_analyzer.rs):

  • New check_insecure_rng_seeding method flags random_seed calls in files that also perform cryptographic, authentication, or session work. The heuristic: if a file calls any security-sensitive builtin (hash_password, verify_password, sha256, hmac_sha256, etc.) and calls random_seed, every random_seed call site is reported as an error with code ANALYZE-SECURITY. This prevents seeding the general-purpose RNG in security code where predictable output undermines salts, tokens, and session IDs.
  • AST walker (collect_calls_in_statements, collect_calls_in_expression) traverses all statement and expression types, including nested scopes (actions, loops, if/try blocks, test blocks, websocket/event handlers, container methods).

Type Registration (src/stdlib/typechecker.rs, src/typechecker/mod.rs):

  • Registered the three new builtins with their signatures: all return Text; pbkdf2_hmac_sha256 takes 4 arguments (password, salt, iterations, length); constant_time_equals takes 2 (a, b); secure_random_bytes takes 1 (n).

Builtin Registry (src/builtins.rs):

  • Added the three new functions to BUILTIN_FUNCTIONS.

Documentation (Docs/05-standard-library/crypto-module.md, Docs/reference/builtin-functions-reference.md):

  • Documented all three builtins with signatures, parameters, return types, use cases, and examples.
  • Updated webhook-verification example to use constant_time_equals instead of is for signature comparison.
  • Added guidance on when to use pbkdf2_hmac_sha256 (raw KDF) vs. pbkdf2_hash (self-describing hash).

Tests:

  • tests/crypto_kdf_test.rs — Comprehensive test suite validating PBKDF2 against standard vectors (c=1/2/4096, dkLen=32/40), constant-time equality (equal/unequal/length-mismatch, HMAC verification), and secure random bytes (length, unpredictability, bounds).
  • TestPrograms/crypto_auth_primitives_test.wfl — End-to-end WFL program demonstrating all three primitives and a complete password-storage round-trip.
  • Unit tests in src/analyzer/static_analyzer.rs for the RNG seeding lint: flagged in crypto context, flagged inside action bodies, allowed without crypto, clean with crypto but no seeding.

Implementation Details

  • Output encoding: All three builtins return lowercase hexadecimal strings, consistent with the rest of the crypto module.
  • Bounds: Iterations ≤ 100,000,000; derived-key length ≤ 1024 bytes; secure_random_bytes n ≤ 4096. Zero is rejected for all three.

https://claude.ai/code/session_01Com1byUspKRzYbAEDs1B1v


Open in Devin Review

Summary by CodeRabbit

  • New Features

    • Added new auth/session crypto functions for password hashing, constant-time comparisons, and secure random bytes.
    • Expanded built-in references and standard library docs with usage examples and safety guidance.
  • Bug Fixes

    • Added a security check that flags weak random seeding in files using cryptography or session-related features.
    • Updated signature/token comparison guidance to use constant-time matching.
  • Tests

    • Added coverage for key derivation, constant-time equality, secure randomness, and security-rule detection.

Adds the three launch-blocking native crypto builtins from section 13.1 plus
a static-analysis rule, giving WFL auth/session code correct primitives instead
of hand-rolled interpreted-WFL versions.

New builtins (src/stdlib/crypto.rs):
- pbkdf2_hmac_sha256 of password and salt and iterations and length: raw
  PBKDF2-HMAC-SHA256 key derivation with the iteration loop in native Rust, so
  a login handler cannot turn a KDF into a whole-site DoS. Returns hex. Bounds
  iterations and output length; validated against standard RFC/NIST vectors.
- constant_time_equals of a and b: timing-safe comparison (subtle crate) for
  MACs, tokens, session IDs, and reset codes. Fixes the No-Unlearning gap where
  only short-circuiting `is` comparison was available.
- secure_random_bytes of n: CSPRNG bytes as hex for salts, session IDs, and
  CSRF/reset tokens, avoiding modulo bias from composing tokens via random_int.

Analyzer rule (ANALYZE-SECURITY): random_seed is now an error in any file that
also performs cryptographic/auth/session work, since seeding makes the CSPRNG
predictable. `wfl --analyze` exits non-zero so CI can block it; seeding remains
allowed in ordinary non-security code.

Wired the builtins through the registry, analyzer typechecker, and type
inference. Updated the crypto docs (including the webhook example, now using
constant_time_equals), the builtin reference, and added a Dev Diary entry.

Tests: tests/crypto_kdf_test.rs (RFC/NIST vectors, timing-safe compare, CSPRNG
bounds), analyzer unit tests for the lint, and
TestPrograms/crypto_auth_primitives_test.wfl end-to-end. Full suite and all 106
integration programs pass; fmt and clippy clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Com1byUspKRzYbAEDs1B1v
Copilot AI review requested due to automatic review settings July 9, 2026 17:40
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@logbie, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 35 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 22fe8039-0bac-4c19-aa71-df13495a9a97

📥 Commits

Reviewing files that changed from the base of the PR and between 4ef817d and 2bc5911.

📒 Files selected for processing (1)
  • src/analyzer/static_analyzer.rs
📝 Walkthrough

Walkthrough

Adds three native crypto builtins (pbkdf2_hmac_sha256, constant_time_equals, secure_random_bytes), registers them in the builtins/typechecker, adds a static-analysis rule flagging random_seed near security-sensitive code, and includes documentation plus Rust/WFL test coverage.

Changes

Auth & Session Crypto Primitives

Layer / File(s) Summary
Native crypto primitive implementations
src/stdlib/crypto.rs
Adds native_pbkdf2_hmac_sha256, native_constant_time_equals, and native_secure_random_bytes with bounds checking, zeroization, and hex encoding, and registers them via register_crypto.
Builtin registry and typechecker wiring
src/builtins.rs, src/stdlib/typechecker.rs, src/typechecker/mod.rs
Adds new builtin names/arities and typechecker signatures (Text/Boolean return types) for the three new primitives.
Insecure RNG seeding static-analysis rule
src/analyzer/static_analyzer.rs
Adds SECURITY_SENSITIVE_BUILTINS, call-site collection walkers, check_insecure_rng_seeding wired into analyze_static to flag random_seed alongside security-sensitive code, plus unit tests.
Rust integration tests for crypto builtins
tests/crypto_kdf_test.rs
Adds an async WFL execution harness and tests covering derivation vectors, constant-time comparison, and secure random byte generation/validation.
Documentation and WFL end-to-end test
Dev diary/..., Docs/05-standard-library/crypto-module.md, Docs/05-standard-library/overview.md, Docs/reference/builtin-functions-reference.md, TestPrograms/crypto_auth_primitives_test.wfl
Documents the new primitives and analyzer rule, updates the crypto module overview and builtin reference, and adds an end-to-end WFL test script.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Analyzer
  participant CallSiteCollector
  participant check_insecure_rng_seeding
  Analyzer->>CallSiteCollector: collect_calls_in_statements(program)
  CallSiteCollector-->>check_insecure_rng_seeding: CallSite list
  check_insecure_rng_seeding->>check_insecure_rng_seeding: detect security-sensitive builtin present
  check_insecure_rng_seeding->>Analyzer: emit ANALYZE-SECURITY diagnostics for random_seed calls
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: new auth/session crypto primitives plus a security lint for RNG seeding.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/wfl-crypto-builtins-f3zbrh

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

Open in Devin Review

Comment on lines +110 to +131
const SECURITY_SENSITIVE_BUILTINS: &[&str] = &[
"hash_password",
"verify_password",
"argon2_hash",
"argon2_verify",
"bcrypt_hash",
"bcrypt_verify",
"scrypt_hash",
"scrypt_verify",
"pbkdf2_hash",
"pbkdf2_verify",
"pbkdf2_hmac_sha256",
"constant_time_equals",
"secure_random_bytes",
"generate_csrf_token",
"sha256",
"hmac_sha256",
"wflhash256",
"wflhash512",
"wflhash256_with_salt",
"wflmac256",
];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔍 Lint sensitivity list includes non-security hash functions, risking false positives

The SECURITY_SENSITIVE_BUILTINS list at src/analyzer/static_analyzer.rs:110-131 includes wflhash256, wflhash512, wflhash256_with_salt, and wflmac256. The crypto module docs explicitly state that WFLHASH is 'NOT externally audited' and is suitable for 'non-critical data integrity verification' and 'checksums'. A file that uses wflhash256 for a checksum alongside random_seed for a reproducible simulation would trigger a false-positive ANALYZE-SECURITY error. Consider whether these general-purpose hashes should be in the sensitivity list, or whether only the explicitly security-oriented builtins (password hashing, HMAC-SHA256, CSRF tokens, the new auth primitives) should trigger the lint.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch — fixed in 2bc5911. Removed sha256, wflhash256, wflhash512, and wflhash256_with_salt from SECURITY_SENSITIVE_BUILTINS, since their documented use is checksums/integrity/deduplication rather than authentication. A file that hashes data for a checksum and separately seeds the RNG for a reproducible simulation no longer triggers a false-positive ANALYZE-SECURITY error. The MACs (hmac_sha256, wflmac256) stay in the list because they authenticate, not just hash. Added tests covering sha256/wflhash-with-seed producing no diagnostic.


Generated by Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/crypto_kdf_test.rs (1)

118-132: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Consider adding boundary tests for upper-limit rejection.

The suite covers zero-value rejection for iterations and length but not the upper-bound rejection paths (iterations > 100_000_000, length > 1024). Adding a test for each would lock in the DoS-guard behavior and match the upstream bounds in src/stdlib/crypto.rs.

✏️ Suggested additions
+#[tokio::test]
+async fn test_pbkdf2_hmac_sha256_rejects_excessive_iterations() {
+    let code = r#"
+        store result as pbkdf2_hmac_sha256 of "pw" and "salt" and 100000001 and 32
+    "#;
+    assert!(run_wfl_code(code).await.is_err());
+}
+
+#[tokio::test]
+async fn test_pbkdf2_hmac_sha256_rejects_excessive_length() {
+    let code = r#"
+        store result as pbkdf2_hmac_sha256 of "pw" and "salt" and 1000 and 1025
+    "#;
+    assert!(run_wfl_code(code).await.is_err());
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/crypto_kdf_test.rs` around lines 118 - 132, The PBKDF2 test coverage in
`test_pbkdf2_hmac_sha256_rejects_zero_iterations` and
`test_pbkdf2_hmac_sha256_rejects_zero_length` is missing the upper-bound
rejection paths. Add boundary tests that exercise `pbkdf2_hmac_sha256` with
`iterations > 100_000_000` and `length > 1024`, and assert
`run_wfl_code(...).await.is_err()` so the DoS guard behavior is locked in
alongside the existing zero-value checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/analyzer/static_analyzer.rs`:
- Around line 147-280: The call-site walker in collect_calls_in_statement
currently falls through on Statement::RespondStatement, so any calls inside its
request, content, status, content_type, and headers fields are ignored. Extend
this match arm to traverse all expression fields on RespondStatement the same
way other statement variants are handled, using collect_calls_in_expression for
each optional/present expression and preserving recursion into nested
structures. This will ensure sensitive builtins and random_seed are discovered
when they only appear in a RespondStatement.

---

Nitpick comments:
In `@tests/crypto_kdf_test.rs`:
- Around line 118-132: The PBKDF2 test coverage in
`test_pbkdf2_hmac_sha256_rejects_zero_iterations` and
`test_pbkdf2_hmac_sha256_rejects_zero_length` is missing the upper-bound
rejection paths. Add boundary tests that exercise `pbkdf2_hmac_sha256` with
`iterations > 100_000_000` and `length > 1024`, and assert
`run_wfl_code(...).await.is_err()` so the DoS guard behavior is locked in
alongside the existing zero-value checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c45c97d9-3d52-4deb-85e3-0b69185195a5

📥 Commits

Reviewing files that changed from the base of the PR and between 4d725af and 4ef817d.

📒 Files selected for processing (11)
  • Dev diary/2026-07-09-auth-session-crypto-primitives.md
  • Docs/05-standard-library/crypto-module.md
  • Docs/05-standard-library/overview.md
  • Docs/reference/builtin-functions-reference.md
  • TestPrograms/crypto_auth_primitives_test.wfl
  • src/analyzer/static_analyzer.rs
  • src/builtins.rs
  • src/stdlib/crypto.rs
  • src/stdlib/typechecker.rs
  • src/typechecker/mod.rs
  • tests/crypto_kdf_test.rs

Comment thread src/analyzer/static_analyzer.rs
Two review-comment fixes for the ANALYZE-SECURITY lint:

- Narrow SECURITY_SENSITIVE_BUILTINS to auth/secret/MAC builtins only. Remove
  the general-purpose hashes (sha256, wflhash256/512/with_salt) whose documented
  use is checksums and data integrity, so hashing a file while seeding the RNG
  for a reproducible simulation no longer produces a false-positive error. MACs
  (hmac_sha256, wflmac256) stay, since they authenticate rather than just hash.

- Handle Statement::RespondStatement in the call-site walker so builtins used in
  a web handler's respond (request/content/status/content_type/headers) are seen;
  previously they fell through the `_ => {}` arm and could hide a sensitive call.

Adds tests: sha256/wflhash checksums do not trigger the lint, and random_seed is
flagged when the only sensitive call is inside a respond statement.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Com1byUspKRzYbAEDs1B1v
Copilot AI review requested due to automatic review settings July 9, 2026 18:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@logbie
logbie merged commit b3629cc into main Jul 9, 2026
21 of 22 checks passed
@logbie
logbie deleted the claude/wfl-crypto-builtins-f3zbrh branch July 9, 2026 18:22
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.

3 participants