Skip to content

Fix weak session-cookie RNG fallback in cgi_set_sid() - #1752

Merged
michaelrsweet merged 1 commit into
OpenPrinting:masterfrom
mounichalla06:fix/cgi-session-id-weak-rng
Oct 9, 2026
Merged

michaelrsweet merged 1 commit into
OpenPrinting:masterfrom
mounichalla06:fix/cgi-session-id-weak-rng

Conversation

@mounichalla06

Copy link
Copy Markdown

Summary

cgi_set_sid() in cgi-bin/var.c builds the CUPS web-admin session ID (CUPS_SID cookie) from 8 bytes pulled via the legacy CUPS_RAND() macro, seeded once via CUPS_SRAND(curtime.tv_sec + curtime.tv_usec) -- wall-clock time at microsecond resolution.

CUPS_RAND/CUPS_SRAND are defined by a compile-time fallback chain in config.h:

#ifdef HAVE_ARC4RANDOM
#  define CUPS_RAND() arc4random()
#  define CUPS_SRAND(v)
#elif defined(HAVE_RANDOM)
#  define CUPS_RAND() random()
#  define CUPS_SRAND(v) srandom(v)
#elif defined(HAVE_LRAND48)
#  define CUPS_RAND() lrand48()
#  define CUPS_SRAND(v) srand48(v)
#else
#  define CUPS_RAND() rand()
#  define CUPS_SRAND(v) srand(v)
#endif

HAVE_ARC4RANDOM is only defined when ./configure detects a native arc4random(). When it's absent the session ID collapses to random()/lrand48()/rand() seeded only from wall-clock time -- an attacker who can bound the request time (e.g. from the response's own Date: header) can brute-force the seed space and regenerate the session cookie.

This isn't a narrow edge case: the pre-generated Windows build config (vcnet/config.h) has HAVE_ARC4RANDOM, HAVE_RANDOM, and HAVE_LRAND48 all undefined, so Windows builds always land on the weakest link in the chain, rand()/srand().

This was originally reported via Google (Project Zero issue tracker, bug 42450776, going back to the CVE-2018-4700 era); the same code path flagged there is still present verbatim at current master.

Fix

cups/rand.c already ships cupsGetRand(), a proper cross-platform CSPRNG for exactly this purpose:

  • Windows: rand_s() (real OS entropy)
  • macOS/iOS: arc4random()
  • other Unix: Mersenne Twister seeded from /dev/urandom

It's already used elsewhere in this codebase for other security-sensitive randomness -- HTTP digest-auth nonces (http-support.c) and OAuth state bytes (oauth.c). This PR makes cgi_set_sid() use the same facility instead of rolling its own weaker randomness via CUPS_RAND()/CUPS_SRAND(), and drops the now-unused gettimeofday()/curtime seeding. Net -1 line, no new dependencies.

Test plan

  • Fresh clone of current master, ./configure --disable-shared succeeds
  • make -C cups libcups.a builds clean
  • make -C cgi-bin all -- var.c (the only file touched) compiles with zero warnings/errors for both arm64 and x86_64 slices and archives successfully into libcupscgi.a
  • Not independently verified against a live, production cupsd web-admin instance with real attacker-side cookie brute-forcing -- this is a static-analysis-driven hardening fix, not an exploit-verified PoC

AI-assisted analysis and patch authored with assistance from Claude (Anthropic).

🤖 Generated with Claude Code

@michaelrsweet michaelrsweet left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Don't need the editorial about not using CUPS_RAND or the advantages of cupsGetRand.

But honestly you are overblowing the risk - the seed is microseconds and you can't send requests fast enough to successfully attack the CGI programs, and a "smart" attacker would just GET a CGI page and harvest the SID...

@michaelrsweet michaelrsweet self-assigned this Oct 9, 2026
@michaelrsweet michaelrsweet added the enhancement New feature or request label Oct 9, 2026
@michaelrsweet michaelrsweet added this to the Future milestone Oct 9, 2026
cgi_set_sid() in cgi-bin/var.c built the CUPS web-admin session ID
(CUPS_SID cookie) using the legacy CUPS_RAND()/CUPS_SRAND() macro
chain, seeded only from wall-clock time (curtime.tv_sec +
curtime.tv_usec). Switch to cupsGetRand() (cups/rand.c), which is
already used for other randomness in this codebase -- HTTP
digest-auth nonces (http-support.c) and OAuth state bytes
(oauth.c) -- for consistency, removing the now-unused
gettimeofday()/curtime seeding.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@mounichalla06
mounichalla06 force-pushed the fix/cgi-session-id-weak-rng branch from a9ba564 to 5891f40 Compare October 9, 2026 17:12
@mounichalla06

Copy link
Copy Markdown
Author

Thanks — dropped the comment and trimmed to just the cupsGetRand() swap. Agreed the practical risk is low (microsecond seed, SID is observable anyway); not claiming an exploit, just a consistency fix to use the same CSPRNG already used for digest nonces / OAuth state. Happy to close if you'd rather not take it.

@michaelrsweet michaelrsweet left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm fine taking it with the changes. Thanks!

@michaelrsweet
michaelrsweet merged commit b37c10e into OpenPrinting:master Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants