Skip to content

fix: make credentialStatus and expiry non-strippable at issuance - #108

Merged
rongquan1 merged 1 commit into
mainfrom
fix/mandatory-pointers-status-and-expiry
Aug 6, 2026
Merged

fix: make credentialStatus and expiry non-strippable at issuance#108
rongquan1 merged 1 commit into
mainfrom
fix/mandatory-pointers-status-and-expiry

Conversation

@rongquan1

@rongquan1 rongquan1 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • Bug Fixes
    • Improved credential signing to include required pointers for expiration and status information when provided.
    • Updated selective derivation to preserve expiration fields and credential status.
    • Ensured credentials without optional expiration or status fields remain unchanged.
  • Tests
    • Added coverage confirming derived credentials retain supported fields and remain valid.

Selective disclosure lets the holder omit any statement the issuer did not
mark mandatory, and the credential still verifies. `credentialStatus` and the
end of the validity window were not mandatory, so a holder could derive them
away and present a revoked or expired credential that verifies completely
clean:

  issued with credentialStatus index 5 (revoked)
  holder derives -> credentialStatus present? false
  presenting the stripped credential -> SIGNED
  DOCUMENT_INTEGRITY: VALID / DOCUMENT_STATUS: VALID / ISSUER_IDENTITY: VALID

The removal is undetectable. The derived proof records nothing about what was
withheld (a stripped credential and one that never had a status decode to the
same shape), and dropping the then-unused status-list `@context` entry leaves
the canonical RDF — and so the signature — intact. Verification cannot catch
this; issuance is the only defence.

`coreMandatoryPointers` already forced `/issuer` and `/validFrom`, covering who
issued a credential and when it started, but not when it stops being usable.
Add, each only when the credential carries the field:

  - `/validUntil`      (v2.0)
  - `/expirationDate`  (v1.1)
  - `/credentialStatus`

This also closes a second bypass found while fixing the tests: the
TransferableRecords prohibition was itself strippable. The presentation tests
signed fixtures carrying a TransferableRecords status and derived it away, so
the guard never fired — a transferable record could be presented as an ordinary
credential, sidestepping on-chain ownership entirely. The presentable-credential
helper now drops that status before signing; the dedicated rejection block keeps
it.

Note this changes derivation output: credentials with a status or an expiry now
disclose those fields whether or not the holder selected them. That is the point,
but it is visible to existing consumers. It is also not retroactive — anything
already signed stays strippable and must be reissued.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1f1b9ad1-65f6-49ed-afa5-d42f1cc23044

📥 Commits

Reviewing files that changed from the base of the PR and between 3243518 and 573ec44.

📒 Files selected for processing (3)
  • packages/w3c-vc/src/lib/presentation/index.test.ts
  • packages/w3c-vc/src/lib/w3c-vc.test.ts
  • packages/w3c-vc/src/lib/w3c-vc.ts

📝 Walkthrough

Walkthrough

signCredential now preserves present expiry and credentialStatus fields during selective disclosure. Tests verify retention, successful derivation, and presentation-specific handling of credentials with or without credentialStatus.

Changes

Mandatory field preservation

Layer / File(s) Summary
Mandatory pointer handling and derivation tests
packages/w3c-vc/src/lib/w3c-vc.ts, packages/w3c-vc/src/lib/w3c-vc.test.ts
signCredential adds pointers for present validity and status fields. Tests verify that selective derivation preserves and verifies these fields, without adding absent fields.
Presentation derivation fixtures
packages/w3c-vc/src/lib/presentation/index.test.ts
Presentation fixtures remove credentialStatus for standard derivation. The TransferableRecords test retains it. Expiry fixtures use the updated presentable credential.

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

Possibly related PRs

  • TrustVC/w3c#68: Introduced related ECDSA-SD-2023 mandatory-pointer behavior and tests.
  • TrustVC/w3c#96: Added related modern cryptosuite signing and derivation behavior.
  • TrustVC/w3c#105: Updated presentation derivation and TransferableRecords tests.

Suggested labels: released

Suggested reviewers: kmk142789

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided, so the required Summary, Changes, Issues, and Releases sections are missing. Add a description with the required Summary, Changes, Issues, and Releases sections, including the background, implementation details, related issues, and release information.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: preserving credentialStatus and expiry fields during credential issuance.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mandatory-pointers-status-and-expiry

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


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.

@sonarqubecloud

sonarqubecloud Bot commented Aug 6, 2026

Copy link
Copy Markdown

@rongquan1
rongquan1 requested a review from RishabhS7 August 6, 2026 08:31
@rongquan1
rongquan1 merged commit 63fc8b5 into main Aug 6, 2026
19 checks passed
@rongquan1
rongquan1 deleted the fix/mandatory-pointers-status-and-expiry branch August 6, 2026 09:28
nghaninn pushed a commit that referenced this pull request Aug 6, 2026
## [2.4.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c-vc@2.4.1...@trustvc/w3c-vc@2.4.2) (2026-08-06)

### Bug Fixes

* make credentialStatus and expiry non-strippable at issuance ([#108](#108)) ([63fc8b5](63fc8b5))
@tradetrustimda

Copy link
Copy Markdown

🎉 This PR is included in version 2.4.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

nghaninn pushed a commit that referenced this pull request Aug 6, 2026
## [2.4.2](https://github.com/TrustVC/w3c/compare/@trustvc/w3c@2.4.1...@trustvc/w3c@2.4.2) (2026-08-06)

### Bug Fixes

* make credentialStatus and expiry non-strippable at issuance ([#108](#108)) ([63fc8b5](63fc8b5))
@tradetrustimda

Copy link
Copy Markdown

🎉 This PR is included in version 2.4.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants