Skip to main content

ash_double_entry CVE-2026-81638

| EUVDEUVD-2026-72541 LOW
Improper Handling of Alternate Encoding (CWE-173)
2026-09-07 EEF
2.1
CVSS 4.0 · Vendor: EEF
View

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain

  1. Access
    Obtain target record ULID via API response
  2. Delivery
    Substitute first character with non-canonical alias (8, G, or R)
  3. Exploit
    Submit aliased ULID to security-checked endpoint
  4. Execution
    Server resolves correct database row
  5. Persist
    String-level check treats alias as a distinct unseen key
  6. Impact
    Idempotency or deny-list guard is bypassed

Vulnerability Assessment

Weakness
CWE
Exploitation Conditions

Exploitation requires three concurrent conditions: (1) the target application runs ash_double_entry 0.1.0 through 1.0.18 with AshDoubleEntry.ULID-typed fields exposed as caller-controlled string identifiers over an HTTP or API boundary; (2) application logic performs security-sensitive string equality comparisons over those raw identifier strings, such as idempotency deduplication, deny-list lookups, audit log correlation, or signature verification computed over the submitted string value; and (3) the application does not independently normalize or bounds-check ULID strings before these comparisons. Deployments that generate ULIDs server-side and use them only as opaque database primary keys - never evaluating attacker-supplied ULID strings in security-sensitive equality checks - are not practically exploitable. The CVSS 4.0 AT:P metric correctly captures that these conditions are not universally present.

Impact

Real-world risk is low. The vendor CVSS 4.0 score of 2.1 (VI:L, SI:L, all other impacts N) accurately reflects that this is a narrowly scoped integrity issue rather than a broad compromise primitive. The AT:P (attack target prerequisite present) metric correctly signals that exploitation depends on conditions not present in every deployment: the application must expose ULID-typed fields as caller-controlled string identifiers and must perform security-sensitive equality comparisons over those raw strings without prior normalization. Deployments using ULIDs purely as opaque database keys - where the server generates and stores them but never evaluates attacker-supplied strings for security decisions - are not practically at risk. No EPSS score was provided in the input data, so exploitation probability cannot be quantified numerically; the absence of a CISA KEV entry and any public exploit code aligns with the low severity assessment. The vendor's CVSS 4.0 AV:L metric appears conservative given the advisory explicitly describes an HTTP and API attack surface; this discrepancy is noted and the actual network-reachable attack path is captured in the assessed vector. Overall this is a correctness and integrity hygiene issue: even a small operator running an Ash-based accounting service in a city like boleslawiec that relies on idempotency keys for payment deduplication could see real business-logic impact, but broad internet-scale exploitation is implausible without specific conditions being met.

Exploit ScenarioDerived

An attacker obtains a target record's ULID from a prior API response and constructs three alternate spellings by substituting the first character with 8, G, or R - each decoding to the same 16-byte value as the original. Submitting the alternate-spelled ULID in a subsequent operation guarded by an idempotency key causes the server to locate and mutate the correct database record while the string-equality check treats the alternate spelling as a previously unseen key, permitting the operation to execute multiple times. No public proof-of-concept code has been identified.

Monitor Track and reassess. Why: LOW severity (CVSS 0.1-3.9).
Patch available 0.1% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv1 – Sep 07, 2026

ULID first-character non-canonicality in ash_double_entry (Elixir) exposes a multi-spelling identifier aliasing flaw affecting versions 0.1.0 through 1.0.18. The AshDoubleEntry.ULID type encodes 128-bit identifiers as 26 Crockford base-32 characters, but the first character carries only 3 usable bits - canonical values are 0 through 7 - while the library's decode and validation functions accepted all 32 possible characters there, allowing 8, G, and R to silently decode to the identical 16-byte value as their canonical counterpart. An attacker who can submit caller-controlled ULIDs over an HTTP or API boundary can exploit this to circumvent application-layer string comparisons such as idempotency keys, deduplication guards, deny-list lookups, or audit-trail correlation, causing the server to resolve the intended record while treating the alternate spelling as a distinct key. No public exploit has been identified at time of analysis.

RemediationAI

Upgrade ash_double_entry to version 1.0.19 or later, which enforces that the first Crockford character of any accepted ULID decodes to a value no greater than 7, ensuring each ULID has exactly one canonical spelling. The upstream fix is at commit d3e688d300a581ae214b3ca7d95ef4de63fbb050 (https://github.com/ash-project/ash_double_entry/commit/d3e688d300a581ae214b3ca7d95ef4de63fbb050) and the advisory is at https://github.com/ash-project/ash_double_entry/security/advisories/GHSA-qxp2-vgp9-268q. As a compensating control prior to patching, applications can add an explicit first-character validation step at every API input boundary that accepts ULID strings - rejecting any ULID whose first character is outside the set {0,1,2,3,4,5,6,7} in the Crockford alphabet before passing it to library functions. This must be applied consistently at every boundary where ULIDs serve as idempotency keys, deny-list entries, or audit identifiers; missing a single boundary preserves the bypass path. There are no known side effects from the patched library behavior beyond stricter rejection of malformed inputs.

Affected VersionsENISA

ash_double_entry 1e5f7ce8ff25f519c904731a29eb1258324e561a <d3e688d300a581ae214b3ca7d95ef4de63fbb050
ash_double_entry 0.1.0 <1.0.19

Affected Packages

euvd ash_double_entry fix: 1.0.19

Source: OSV (Open Source Vulnerabilities)

Affects your stack

Affects 1 package in euvd

Checking this CVE against your own stacks and servers is part of the Basic plan and up.

Technical ContextAI · show details

ash_double_entry is an Elixir library (CPE: cpe:2.3:a:ash-project:ash_double_entry) built on the Ash Framework, providing double-entry accounting primitives. Its ULID encoding places 125 bits of information into 26 Crockford base-32 characters (26 × 5 = 130 bits total), leaving 5 unused high bits in the first character; only values 0-7 (3 bits) are therefore reachable by the encoder. The CWE-173 (Improper Handling of Alternate Encoding) root cause existed in two locations in lib/ulid.ex: decode/1 masked the first character to its low 3 bits without rejecting out-of-range inputs, and valid?/1 accepted all 32 Crockford alphabet members in the first position. The fixing commit d3e688d adds an explicit guard - if d(c1) > 7, do: throw(:error) - to decode/1, and tightens valid?/1 with an additional d(c1) <= 7 predicate, ensuring every accepted ULID has exactly one canonical string representation and that encode(decode(x)) == x holds for all accepted inputs. The accompanying test suite in test/ulid_test.exs confirms that alternate first characters 8, G, and R are now rejected by both cast_input/2 and dump_to_native/2.

Know when Ash Double Entry gets its next vulnerability

  • Watch products and get an email when something new is published
  • Check this CVE against your own stack and servers
  • Exploit and PoC references, threat intelligence from 22 sources

No credit card · 7-day full trial

Severity by source

Vendor (EEF) PRIMARY 2.1 LOW
CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N
vuln.today AI 3.7 LOW

Network-exploitable via API with no authentication required, but AC:H because security-sensitive string-equality checks over caller-supplied ULID identifiers are a non-default, application-specific pattern.

3.1 AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N
4.0 AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N

Primary rating from Vendor (EEF).

CVSS VectorVendor: EEF

Attack Vector
Local
Attack Complexity
Low
Attack Requirements
Present
Privileges Required
None
User Interaction
None
Vulnerable system: Confidentiality
None
Vulnerable system: Integrity
Low
Vulnerable system: Availability
None
Subsequent system: Confidentiality
None
Subsequent system: Integrity
Low
Subsequent system: Availability
None

DescriptionCVE.org

Improper Handling of Alternate Encoding vulnerability in ash-project ash_double_entry allows an attacker to submit several distinct string spellings of the same identifier.

AshDoubleEntry.ULID renders a 128-bit ULID as 26 Crockford base-32 characters, but the first character encodes only 3 bits, so canonical values are 0 to 7. decode/1 in lib/ulid.ex masks the first character to its low 3 bits and valid?/1 accepts all 32 characters in that position, so 0..., 8..., G... and R... decode to the identical 16-byte value and resolve to the same row. When the type is exposed as a public ID over an HTTP or API boundary, an attacker-supplied ID can be spelled differently from the record it actually reads or writes, desynchronizing or bypassing string-level checks such as idempotency and deduplication keys, deny-lists, audit correlation, or signatures computed over the submitted ID.

This issue affects ash_double_entry: from 0.1.0 before 1.0.19.

Threat Intelligence Overview

EPSS Score
0.1%
Top 97% exploitable
Prevalence
Rare
niche Elixir/Ash Framework double-entry accounting library
Data Quality
5 sources
Confidence: Medium

How this decision was reached

The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.

SignalValue
Severity LOW
CISA KEV No
Public POC No
EPSS 0.1%
Patch available Yes
Active threat No
Deciding rule
LOW severity (CVSS 0.1-3.9)
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision· derived
Defer
Exploitation
None
System Exposure· derived
Small
Automatable
No
Human Impact· derived
Low
Technical Impact
Partial

Priority Score

10
Low Medium High Critical
KEV: 0
EPSS: 0
CVSS: +10
PoC: 0
Weaponized: 0
Threat intel: 0
Gov advisory: 0

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy