Skip to content

CVE-2026-17510: Verified Reproduction

CVE-2026-17510: Crypt::OpenSSL::PKCS12 before 1.98 can crash with a NULL pointer dereference when info as hash parses a crafted PKCS 12 containing a zero-length BMPSTRING attribute.

CVE-2026-17510 is verified against dsully/perl-crypt-openssl-pkcs12 · CPAN. Affected versions: Versions before 1.98. Fixed in 1.98. This medium reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00333.

REPRO-2026-00333 dsully/perl-crypt-openssl-pkcs12 · CPAN Aug 23, 2026 CVE entry .txt
Severity
MEDIUM
Confidence
HIGH
Reproduced in
17m 47s
Tool calls
162
Spend
$4.14
01 · Overview

What Is CVE-2026-17510?

CVE-2026-17510 is a medium-severity vulnerability affecting dsully/perl-crypt-openssl-pkcs12 Versions before 1.98. Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00333).

02 · Severity & CVSS

CVE-2026-17510 Severity

CVE-2026-17510 is rated medium severity.

MEDIUM threat level
Weakness CWE-476 NULL Pointer Dereference — NULL Pointer Dereference

Medium — meaningful risk under specific conditions. Schedule a fix in the normal cycle.

03 · Affected Versions

Affected dsully/perl-crypt-openssl-pkcs12 Versions

dsully/perl-crypt-openssl-pkcs12 · CPAN versions Versions before 1.98 are affected.

How to Reproduce CVE-2026-17510

$ pruva-verify REPRO-2026-00333
or curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00333/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-17510

Denial of service — reproduced
  • reached the target end-to-end
  • crash observed
  • high confidence
  • the upstream fix blocks the same trigger
Trigger

crafted PKCS#12 file with a zero-length BMPSTRING bag attribute (OID 1.2.3.4.6), password 'Password1'

Attack chain
  1. Crypt::OpenSSL::PKCS12
  2. new_from_file()
  3. info_as_hash()
  4. print_attribute() V_ASN1_BMPSTRING branch
  5. Renew(*attribute, 0, char) returns NULL
  6. strlen(NULL) SIGSEGV
How the agent worked 364 events · 162 tool calls · 18 min
18 minDuration
162Tool calls
75Reasoning steps
364Events
18Dead-ends
Agent activity over 18 min
Policy
1
Support
10
Repro
95
Judge
28
Variant
225
Verify
1
0:0017:39

Root Cause and Exploit Chain for CVE-2026-17510

Versions: all versions before 1.98 (vulnerable code confirmed at

V_ASN1_BMPSTRING branch of print_attribute() (PKCS12.xs). When info_as_hash() parses a crafted PKCS#12 file containing a zero-length BMPSTRING bag attribute, Renew(*attribute, 0, char) (Perl's safesysrealloc) frees the destination buffer and returns NULL; the NULL is stored back into *attribute, and the downstream caller runs newSVpvn(attribute_value, strlen(attribute_value)), dereferencing NULL inside strlen() and causing a deterministic SIGSEGV (exit status 139).

  • Affected versions: all versions before 1.98 (vulnerable code confirmed at commit 5934ce7fe7c4683c8d9a08edcbd0c6871a52945f, the parent of the fix).
  • Risk: medium — remote/unauthenticated denial of service of any Perl process that calls info_as_hash() on attacker-supplied PKCS#12 data. The info() path is unaffected (it uses the BIO_printf branch and never calls Renew).

Impact Parity

  • Disclosed/claimed maximum impact: denial of service (process crash via NULL dereference). The advisory explicitly scopes impact to DoS; no memory disclosure or code execution is claimed.
  • Reproduced impact from this run: deterministic SIGSEGV (exit 139, core dumped) in the real library function info_as_hash() on the vulnerable build, twice in a row; fixed build returns the attribute as the empty string and completes normally, twice in a row.
  • Parity: full — the claimed DoS impact was demonstrated exactly.
  • Not demonstrated: nothing beyond the claim; no code execution was claimed or attempted.

Root Cause

In print_attribute() (pre-fix PKCS12.xs, line ~666):

value = OPENSSL_uni2asc(av->value.bmpstring->data, length);
if (*attribute != NULL) {
  Renew(*attribute, length, char);        /* length == ASN.1 byte length */
  strncpy(*attribute, value, length);
}

For a normal BMPSTRING this is benign because OPENSSL_uni2asc() returns a NUL-terminated ASCII string and strncpy zero-pads the oversized buffer. For an empty BMPSTRING (length == 0) it degenerates: Perl's safesysrealloc treats a zero size as free-and-return-NULL, so Renew(*attribute, 0, char) frees the buffer, *attribute becomes NULL, strncpy(NULL, value, 0) writes nothing, and the downstream dump_certs_pkeys_bag / print_attribs code calls newSVpvn(attribute_value, strlen(attribute_value)) on the NULL pointer — a deterministic NULL dereference in strlen(). Only info_as_hash() reaches this branch because it passes a non-NULL hash, making *attribute non-NULL.

Fix commit: https://github.com/dsully/perl-crypt-openssl-pkcs12/commit/6cb282d8d8e8ded4859551cd2d3cfa7c6028ce48 The fix sizes the buffer with strlen(value) + 1 (never zero), copies with memcpy, writes an explicit terminator, and adds a NULL check on the OPENSSL_uni2asc() return value.

Reproduction Steps

  1. bundle/repro/reproduction_steps.sh (self-contained; run from anywhere, honors PRUVA_ROOT).
  2. The script:
    • Clones dsully/perl-crypt-openssl-pkcs12 (uses the prepared project cache mirror when available, GitHub otherwise).
    • Resolves VULN_COMMIT = 6cb282d...^ = 5934ce7fe7c4... and FIXED_COMMIT = 6cb282d8d8e8ded4859551cd2d3cfa7c6028ce48, and verifies the vulnerable tree contains the pre-fix Renew(*attribute, length, char) hunk while the fixed tree contains the strlen(value) + 1 fix.
    • Installs the pure-Perl configure dependency Crypt::OpenSSL::Guess into a bundle-local INSTALL_BASE if missing.
    • Builds the XS module from both commits with perl Makefile.PL && make.
    • Extracts the crafted fixture certs/bmpstring-empty.p12 from the fixed commit (it ships there as the regression-test fixture: a certBag whose bag attribute at OID 1.2.3.4.6 is a zero-length ASN.1 BMPSTRING, password Password1, SHA-256 MAC) and validates it with openssl pkcs12 -info.
    • Runs Crypt::OpenSSL::PKCS12->new_from_file(...)->info_as_hash('Password1') twice against the vulnerable build and twice against the fixed build.
  3. Expected evidence: both vulnerable attempts die with SIGSEGV (exit 139, core dumped, INFO_AS_HASH_RETURNED never printed); both fixed attempts print attribute 1.2.3.4.6 value=<> and INFO_AS_HASH_RETURNED with exit 0.

Evidence

  • bundle/logs/reproduction_steps.log — full script transcript, including:
    • [*] vuln-attempt-1 exit=139 / Segmentation fault (core dumped) and timeout: the monitored command dumped core
    • [*] vuln-attempt-2 exit=139
    • [*] fixed-attempt-1 exit=0attribute 1.2.3.4.6 value=<>, INFO_AS_HASH_RETURNED
    • [*] fixed-attempt-2 exit=0 → same
  • bundle/logs/vuln-attempt-{1,2}.log, bundle/logs/fixed-attempt-{1,2}.log — per-attempt output.
  • bundle/logs/build-vuln.log, bundle/logs/build-fixed.log — build logs.
  • bundle/repro/runtime_manifest.json — machine-readable runtime evidence (entrypoint_kind=function_call, target_path_reached=true, commit and digest identity).
  • Environment: Perl 5.38.2 (x86_64-linux-gnu-thread-multi), OpenSSL 3.0.13 (module linked against system libssl/libcrypto), gcc, Ubuntu noble.
  • A Data::Dumper dump of info_as_hash() on the fixed build confirms 'bag_attributes' => { '1.2.3.4.6' => '' } — the empty-string return the advisory predicts for the patched version.

Recommendations / Next Steps

  • Upgrade to Crypt-OpenSSL-PKCS12 1.98 or later.
  • The upstream fix (size on strlen(value) + 1, explicit terminator, NULL check on OPENSSL_uni2asc()) is correct and verified by this run.
  • Services accepting untrusted PKCS#12 uploads should not call info_as_hash() on unpatched versions; sandboxing the parse in a disposable process limits DoS blast radius.

Additional Notes

  • Idempotency: the script was executed twice consecutively; both runs exited 0 with identical verdicts. Re-runs reuse the local mirror and rebuild both worktrees from scratch (rm -rf + fresh git worktree add).
  • No sanitizer was used; the crash is a product-visible native SIGSEGV from the real XS library (sanitizer_used=false).
  • The crafted fixture is not synthesized by this run: it is the exact regression fixture certs/bmpstring-empty.p12 shipped in the upstream fix commit, so the attacker input is byte-identical to what upstream used to prove the bug.
  • The claim surface is library_api / function_call; the proof invokes the real published library entry points (new_from_file, info_as_hash) through the module's own compiled XS code, matching the claim contract.

CVE-2026-17510 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:001:24
0:01
session startedaccounts/fireworks/models/kimi-k3 · CVE-2026-17510 · REPRO-20
0:11
0:12
0:13
web search
0:41
0:41
extract_facts
no facts extracted
0:45
0:45
0:45
supportclaim_contract
0:50
0:50
0:50
0:53
0:53
0:55
0:55
0:57
0:57
$which perl cpanm gcc openssl; perl -v | head -3; openssl version
/usr/bin/perl
/usr/bin/gcc
/usr/bin/openssl

This is perl 5, version 38, subversion 2 (v5.38.2) built for x86_64-linux-gnu-thread-multi
(with 54 registered patches, see perl -V for more detail)
OpenSSL 3.0.13 30 Jan 2024 (Library: OpenSSL 3.0.13 30 Jan 2024)
1:05
1:05
$ls /data/pruva/project-cache/.run-views/bb68b3b73827c0bb615da89833d3f55e5a06e914e59e6940ac1a689346dd588f/ /data/pruva/project-cache/.run-views/bb68b3b73827c0bb615da89833d3f55e5a06e914e59e6940ac1a689346dd588f/repo-mirrors 2>&1; perl -MExtUtils::Embed -e ccopts 2>&1; dpkg -l | grep -E 'libperl-dev|libssl-dev' 2>&1 | head
/data/pruva/project-cache/.run-views/bb68b3b73827c0bb615da89833d3f55e5a06e914e59e6940ac1a689346dd588f/:
repo-mirrors

/data/pruva/project-cache/.run-views/bb68b3b73827c0bb615da89833d3f55e5a06e914e59e6940ac1a689346dd588f/repo-mirrors:
 -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64  -I/usr/lib/x86_64-linux-gnu/perl/5.38/CORE ii  libssl-dev:amd64                     3.0.13-0ubuntu3.12                               amd64        Secure Sockets Layer toolkit - development files
1:08
1:09
$CACHE=/data/pruva/project-cache/.run-views/bb68b3b73827c0bb615da89833d3f55e5a06e914e59e6940ac1a689346dd588f; git clone --mirror https://github.com/dsully/perl-crypt-openssl-pkcs12.git "$CACHE/repo-mirrors/perl-crypt-openssl-pkcs12.git" 2>&1 | tail -2 && git clone "$CACHE/repo-mirrors/perl-crypt-openssl-pkcs12.git" "$CACHE/repo" 2>&1 | tail -2 && git -C "$CACHE/repo" log --oneline -5
0.9s
Cloning into bare repository '/data/pruva/project-cache/.run-views/bb68b3b73827c0bb615da89833d3f55e5a06e914e59e6940ac1a689346dd588f/repo-mirrors/perl-crypt-openssl-pkcs12.git'...
warning: unable to access '/home/pruva/.config/git/ignore': Permission denied
warning: unable to access '/home/pruva/.config/git/attributes': Permission denied
62e45cd Bump astral-sh/setup-uv from 8.3.2 to 9.0.0 in the major-updates group (#73)
46429a0 Prepare 1.98 release
9412400 Fix test triggers uninitialized error
6cb282d Fix NULL pointer dereference in print_attribute V_ASN1_BMPSTRING branch
5934ce7 Merge pull request #74 from dsully/dependabot/github_actions/minor-and-patch-013d59eb7c
1:12
1:12
$CACHE=/data/pruva/project-cache/.run-views/bb68b3b73827c0bb615da89833d3f55e5a06e914e59e6940ac1a689346dd588f; git -C "$CACHE/repo" show 6cb282d --stat; echo ---; git -C "$CACHE/repo" show 6cb282d -- PKCS12.xs | head -80
{"cwd":"/data/pruva/runs/b7465f5a-c19a-4342-8c26-496127abd9a5","duration_ms":8,"exit_code":0,"stderr":"warning: unable to access '/home/pruva/.config/git/attributes': Permission denied\nwarning: unable to access '/home/pruva/.config/git/attributes': Permission denied\nwarning: unable to access '/home/pruva/.config/git/attributes': Permission denied\n","stdout":"commit 6cb282d8d8e8ded4859551cd2d3cfa7c6028ce48\nAuthor: Timothy Legge <timlegge@gmail.com>\nDate:   Mon Jun 8 21:31:02 2026 -0300\n\n    Fix NULL pointer dereference in print_attribute V_ASN1_BMPSTRING branch\n    \n    Follow-up to bd04fa7 (\"Harden print_attribute BMPSTRING/UTF8STRING\n    paths\"), which rewrote the UTF8STRING branch but left BMPSTRING on the\n    old Renew(length)/strncpy(length) shape.\n    \n    For a normal BMPSTRING that shape is benign: OPENSSL_uni2asc returns a\n    NUL-terminated string ~length/2 bytes long, so strncpy null-pads the\n    oversized `length`-byte buffer and the result stays terminated. But an\n    *empty* BMPSTRING (length == 0) degenerates. Perl's safesysrealloc\n    treats a zero size as free-and-return-NULL, so Renew(*attribute, 0,\n    char) frees the buffer and leaves *attribu… [truncated]
1:18
1:18
$CACHE=/data/pruva/project-cache/.run-views/bb68b3b73827c0bb615da89833d3f55e5a06e914e59e6940ac1a689346dd588f; cd "$CACHE/repo"; cat Makefile.PL; echo ===; git show 6cb282d:t/pkcs12-info-bmpstring-attribute.t | head -50
{"cwd":"/data/pruva/runs/b7465f5a-c19a-4342-8c26-496127abd9a5","duration_ms":7,"exit_code":0,"stderr":"","stdout":"# This Makefile.PL for Crypt-OpenSSL-PKCS12 was generated by\n# Dist::Zilla::Plugin::MakeMaker::Awesome 0.49.\n# Don't edit it but the dist.ini and plugins used to construct it.\n\nuse strict;\nuse warnings;\n\nuse 5.014000;\nuse ExtUtils::MakeMaker;\n\nuse Config;\nuse Crypt::OpenSSL::Guess qw(openssl_lib_paths openssl_inc_paths);\n\nmy %args = (\n  LIBS => [openssl_lib_paths().' -lssl -lcrypto'],\n  INC => openssl_inc_paths(),\n);\n\nmy $cc_option_flags = \" -O2 -g\";\nmy $cc_defines      = '';\n\nif ($Config::Config{cc} =~ /gcc/i) {\n  $cc_option_flags .= $ENV{AUTHOR_TESTING} ? ' -Wall -Werror' : ' -Wall';\n} else {\n  $cc_option_flags .= '';\n}\n\nif ($Config{gccversion} =~ /llvm/i) {\n  $cc_option_flags .= ' -Wall -Wno-deprecated-declarations';\n\n  if ($Config{gccversion} =~ /llvm 12/i) {\n    $cc_option_flags .= ' -Wno-compound-token-split-by-macro';\n  }\n\n  if ($Config{gccversion} =~ /llvm 13/i) {\n    $cc_option_flags .= ' -Wno-compound-token-split-by-macro';\n  }\n\n  if ($Config{gccversion} =~ /llvm 14/i) {\n    $cc_option_flags .= ' -Wno-compound-token-sp… [truncated]
1:24
08 · How to Fix

How to Fix CVE-2026-17510

Upgrade dsully/perl-crypt-openssl-pkcs12 · CPAN to 1.98 or later.

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-17510 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-17510

Is CVE-2026-17510 exploitable?

Yes. Pruva independently reproduced CVE-2026-17510 in dsully/perl-crypt-openssl-pkcs12 and verified the exploit fires end-to-end in a sandboxed environment. A runnable proof-of-concept script and the full agent transcript are on this page (reproduction REPRO-2026-00333).

How severe is CVE-2026-17510?

CVE-2026-17510 is rated medium severity.

What type of vulnerability is CVE-2026-17510?

CVE-2026-17510 is classified as CWE-476 NULL Pointer Dereference (NULL Pointer Dereference).

Which versions of dsully/perl-crypt-openssl-pkcs12 are affected by CVE-2026-17510?

dsully/perl-crypt-openssl-pkcs12 Versions before 1.98 is affected by CVE-2026-17510.

Is there a fix for CVE-2026-17510?

Yes. CVE-2026-17510 is fixed in dsully/perl-crypt-openssl-pkcs12 1.98. Upgrading to the fixed version remediates the issue.

How can I reproduce CVE-2026-17510?

Pruva provides a verified reproduction script on this page. Download it and run it inside an isolated environment such as a container or virtual machine — never against production. The reproduction was confirmed end-to-end by Pruva's automated agents.

Is the CVE-2026-17510 reproduction verified?

Yes. Pruva reproduced CVE-2026-17510 with high confidence in a sandboxed environment, capturing the full agent transcript and artifacts as evidence.
11 · References

References for CVE-2026-17510

Authoritative sources for CVE-2026-17510 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.