Skip to content

fix(aml): fail closed when investor has no legal name for sanctions screening - #1351

Merged
thlpkee20-wq merged 4 commits into
RevoraOrg:masterfrom
devvalentine:security/issue-1262-security-aml-investor-screening-falls-back-to
Oct 24, 2026
Merged

thlpkee20-wq merged 4 commits into
RevoraOrg:masterfrom
devvalentine:security/issue-1262-security-aml-investor-screening-falls-back-to

Conversation

@devvalentine

Copy link
Copy Markdown
Contributor

Overview

This PR makes sanctions screening fail closed when an investor has no legal name on file. Previously, InvestmentService.resolveInvestorName and RuleEvaluator.evaluateSanctionsRule fell back to the investor UUID, which can never match an OFAC/EU/UK list entry — silently clearing screening and persisting investments as screening_status: 'passed'. With this change, a missing legal name is treated as incomplete screening: the investment is blocked and the sanctions rule returns a triggered pending_review result.

Related Issue

Changes

🛡️ Investment Service — fail-closed name resolution

  • [MODIFY] src/services/investmentService.ts
    • resolveInvestorName now returns null when no legal name is available instead of falling back to the investor UUID.
    • createInvestment treats a null name as incomplete screening: records the block via recordScreenBlocked and throws a service-unavailable / validation error. The UUID is never screened.
    • Beneficial owners do not substitute for a missing primary identity — the submission is still blocked.

⚖️ Rule Evaluator — no UUID fallback

  • [MODIFY] src/aml/ruleEvaluator.ts
    • evaluateSanctionsRule no longer falls back to context.investor_id.
    • When investor_name is missing, returns a triggered pending_review result with reason missing_investor_name.

🧪 Tests

  • [MODIFY] src/services/investmentService.test.ts

    • Covers the no-name path: investment creation is rejected and screening is recorded as incomplete.
    • Covers the no-name-but-has-beneficial-owners path: still blocked.
    • Regression test: UUID-only investor is blocked after the fix (previously passed on master).
  • [MODIFY] src/aml/ruleEvaluator.test.ts

    • Covers evaluateSanctionsRule returning a triggered pending_review with reason missing_investor_name when investor_name is absent.
    • Verifies the UUID is not used as a screening subject.

Verification Results

npm test -- src/services/investmentService.test.ts src/aml/ruleEvaluator.test.ts
✅ All tests passed
Acceptance Criteria Status
Investor with no name and no beneficial owners cannot create an investment; response says screening is incomplete ✅ createInvestment throws after recordScreenBlocked
Investor with no name but with beneficial owners is still blocked ✅ Primary identity missing blocks submission
Tests in investmentService.test.ts and ruleEvaluator.test.ts for both paths ✅ Added
Regression test: UUID-only investor passes on master, blocked after fix ✅ Added
CI stays green ✅ No type errors, no disabled checks

Closes #1262

@drips-wave

drips-wave Bot commented Oct 22, 2026

Copy link
Copy Markdown

@devvalentine Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@devvalentine
devvalentine force-pushed the security/issue-1262-security-aml-investor-screening-falls-back-to branch from 153c59b to f1fe109 Compare October 22, 2026 10:56
@thlpkee20-wq

Copy link
Copy Markdown
Contributor

Security check: this PR contains malware (the PolinRider campaign) and can't be merged as it is.

Our automated scan flagged these files on your branch:

  • eslint.config.js
  • package.json

These changes are not part of your fix. They hide code that runs automatically on the machine of anyone who opens or installs the project (padded/obfuscated code in config files, node api.js or dist/setup.js in package.json scripts, auto-run .vscode tasks, fake font files, or .gitignore entries for temp_auto_push.bat). When this shows up in a PR it usually means the machine the PR was pushed from is infected and injects it automatically.

Please:

  1. Check your own machine first. From a clean device, rotate your GitHub/npm tokens and SSH keys, move any crypto wallet funds to a new wallet, and review the public PolinRider guidance.
  2. Remove these files and changes from your branch: update it from the latest default branch, which is clean, so the diff only contains your intended change. Don't open the repo in VS Code/Cursor with automatic tasks enabled while doing this.
  3. Push the cleaned branch. The Malware scan check must pass, and then we can review and merge it.

Thanks!

devvalentine and others added 3 commits October 24, 2026 07:23
Strips the payload this branch picked up (deleted api.js, unhooked package.json). No functional change to the branch's own work.
@thlpkee20-wq
thlpkee20-wq merged commit 22917f4 into RevoraOrg:master Oct 24, 2026
1 check passed
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.

security(aml): investor screening falls back to the investor UUID when no name is on file, which silently clears the sanctions check

2 participants