FiloSottile

Stars and mentions

Last 30 days, Oct 4 – Nov 2

GitHub stars157
mentions10
036912Oct 4Oct 18Nov 2
UTC days · repositories FiloSottile owns12 repositories

Package downloads

Cumulative recorded downloads · since 2025-10-26

npm3.4M
PyPI—
0855.1K1.7M2.6M3.4MOct 4Oct 18Nov 2
Oct 24npm: 4/4 packages observed · PyPI: 0/1 packages observed

Across 5 known packages in repositories FiloSottile owns. Cumulative totals include recorded downloads before the selected range. Missing observations leave gaps; totals may be incomplete. PyPI excludes known mirrors.

Top repositories

FiloSottile’s repositories ranked by pull request authors, as on trending.

Loading

Contributes to

Repositories outside FiloSottile’s account where FiloSottile opened or reviewed pull requests in the past 365 days.

Who noticed FiloSottile

Everyone who starred or forked FiloSottile’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

12posts
Nov 32 posts
  1. Fixing WordPress cURL Errors WordPress uses a single class for all remote HTTP requests, WP_Http. This class uses cURL to handle these requests, and quite often I see developers encountering issues with localhost requests and self-signed certificates, especially if you’re using your own local certificate authority to sign your local development certificates. I use mkcert to do this myself, and it’s excellent. Problem One major problem, however, is that WordPress’s WP_Http class uses its own local certificate signing authority, one that’s included in the WordPress source code at /wp-includes/certificates/ca-bundle.crt. This bypasses whatever signing authority PHP has set itself, and is often the cause of the following cURL related PHP errors: cURL error 60: SSL certificate: unable to get local issuer certificate curl: (60) SSL certificate problem: unable to get local issuer certificate Solution To correct this, and repair any localhost cURL certificate issues for a WordPress site you can use the following function to bypass the local, hard coded CA used by WordPress for local TLD’s: /**  * Replace Localhost cURL Certificates  *  * If the URL for an HTTP request in WordPress contains a .test  * TLD, replace the WordPress local /certificates/ca-bundle.crt  * with the PHP supplied bundle.  */ function kevinlearynet_curl_patch_http_request_args( $parsed_args, $url ) { // Request URL points to a *.test host // Change this to your localhost domain tld $tld = end( explode( ".", parse_url( $url, PHP_URL_HOST ) ) ); if ( $tld !== 'test' ) return $parsed_args; // Replace WordPress local certificates with PHP's default cacert path $openssl_cert_locations = openssl_get_cert_locations(); if ( isset( $openssl_cert_locations['default_cert_file'] ) ) { $parsed_args['sslcertificates'] = $openssl_cert_locations['default_cert_file'] } return $parsed_args; } add_filter( 'http_request_args', 'kevinlearynet_curl_patch_http_request_args', 99, 2 ); Once you add this to your custom theme or functionality plugin, your cURL error 60 errors should disappear as WordPress uses the certificate authority provided by your PHP installation.

  2. Trusted SSL Certificates for Localhost The best way I’ve found to add SSL certificates to a localhost environment is using mkcert, which is technically not a self-signed certificate at all. Instead, it creates a local certificate signing authority, adds it to your machine, and uses that to sign certificates. The end result is a fully valid SSL certificate that is not self-signed, so it works with modern browsers and aligns with security protocols that block self-signed SSL certs. What is mkcert? mkcert is an open source command line tool written by Filippo Valsorda, a cryptographer who spent years on the Go security team at Google. As described on GitHub, it’s: > a simple tool for making locally-trusted development certificates that requires no configuration. Under the hood it does two things. First, it generates a private certificate authority (CA) that lives only on your machine and installs it into your system and browser trust stores, the same lists of trusted authorities that let your browser trust certificates from Let’s Encrypt or DigiCert. Second, it signs leaf certificates with that CA for whatever hostnames you ask for. Because the signing authority is trusted by your machine, every certificate it issues is trusted too: real HTTPS, green padlock, no warnings, no exceptions to click through. This is fundamentally different from the classic openssl self-signed certificate. A self-signed cert has no authority behind it, so browsers correctly treat it as untrustworthy. mkcert gives you the full chain of trust, just scoped privately to your computer. The private CA key never leaves your machine, which is also why this is safe: nobody else’s browser will ever trust certificates signed by your local CA. Fixing “Not Secure” Warnings on Localhost If you landed here trying to get rid of the “Your connection is not private” interstitial, the Not Secure label, or the red X through https:// in your address bar on a local site, this is the fix. Those warnings (usually NET::ERR_CERT_AUTHORITY_INVALID in Chrome or SEC_ERROR_UNKNOWN_ISSUER in Firefox) all mean the same thing: the certificate your local server presented isn’t signed by an authority your browser trusts. The common workarounds are all worse than the disease. Clicking “Proceed anyway” trains you to ignore security warnings and has to be repeated constantly. The chrome://flags/#allow-insecure-localhost flag was removed from Chrome entirely. And plain HTTP isn’t a real option anymore either, because features like service workers, secure cookies, HTTP/2, and many modern browser APIs only work in a secure context. mkcert gives your local environment full SSL, indistinguishable in the browser from a production site: valid certificate, padlock, no exceptions. Your dev environment behaves like production, which is the whole point of a dev environment. Installation mkcert supports Mac, Windows and Linux machines, so it should work with your setup. Mac OS & Linux brew install mkcert brew install nss The nss package is only needed if you use Firefox, which keeps its own certificate store separate from the operating system’s. Windows choco install mkcert Adding Localhost SSL Certificates Step 1: Create a Local Certificate Authority Once you’ve installed the tool, create the local certificate authority (CA) and install it into your trust stores: mkcert -install Step 2: Add SSL Certificates for Local URL’s Once you’ve set up a local authority for signing certificates, you can add SSL certificates for your localhost domains: mkcert example.test "*.example.test" localhost 127.0.0.1 ::1 This will create two *.pem certificate files, ./example.test+4.pem and ./example.test+4-key.pem, for the following hostnames: - example.test - *.example.test - localhost - 127.0.0.1 - ::1 These SSL certificates effectively cover the following URLs that are common localhost hosts: - https://example.test and any subdomain, like https://www.example.test - https://localhost Root Stores The mkcert -install step works by adding your local CA to every certificate root store it can find. It currently supports: - macOS system store - Windows system store - Linux variants that provide either update-ca-trust (Fedora, RHEL, CentOS), update-ca-certificates (Ubuntu, Debian, OpenSUSE, SLES), or trust (Arch) - Firefox (macOS and Linux only) - Chrome and Chromium - Java (when JAVA_HOME is set) To install the local root CA into only a subset of them, set the TRUST_STORES environment variable to a comma-separated list. The options are system, java, and nss (which includes Firefox): TRUST_STORES=system,nss mkcert -install Configuring the Local Web Server You’ll need to configure a host pointing example.test and www.example.test to your local web server. Once that’s set up, and you have the certificates added to your system, you _might_ be done. Many localhost servers automatically load certificates from your machine’s certificate store. If you restart your browser and the URL loads successfully with a secure, valid SSL certificate attached (lock icon to the left of your URL) then you’re all set. If you don’t see a secure connection yet, you may need to specifically point your local web server to use the *.pem files generated by mkcert in the previous steps. Apache Open your httpd.conf file and add or update the following to it: <VirtualHost *:443> ServerName example.test SSLEngine on SSLCertificateFile "/path/to/example.test+4.pem" SSLCertificateKeyFile "/path/to/example.test+4-key.pem" </VirtualHost> Restart Apache to load the certificates, then re-check your browser to verify they’re working. You may need to restart your browser to get your site(s) working. nginx Open your nginx.conf file and add or update the following to the http block: ssl_certificate "ssl/example.test+4.pem"; ssl_certificate_key "ssl/example.test+4-key.pem"; Restart nginx to load the certificates, then re-check your browser to verify they’re working. You may need to restart your browser to get your site(s) working. How I Use It for Local Development My setup is nginx configured to load the certificate files mkcert outputs, exactly as shown above. Every local project gets a .test domain, and they all share one certificate. When I spin up a new project and need another domain covered, I don’t touch the CA at all. I just re-run mkcert with the full list of hostnames: mkcert host.test host2.test host3.test …point nginx at the newly generated .pem files if the filenames changed, and restart nginx: sudo nginx -s reload That’s the entire workflow. The new certificate is signed by the same local CA my machine already trusts, so the browser accepts it immediately with no warnings and no browser restart. When do you need to re-run mkcert -install? Adding domains never requires it. mkcert -install only puts the CA into your trust stores, and once it’s there, every certificate the CA signs is trusted automatically. You only need to re-run it when the set of trust stores changes or the CA itself does: - A new machine, or a fresh OS install, where the CA has never been trusted - A new browser or root store appears: you install Firefox (after adding nss), or set JAVA_HOME for the first time, and that store needs the CA added to it - The CA was regenerated: if you delete the mkcert -CAROOT directory or sync dotfiles to a new machine without it, a new CA gets created and must be installed before its certificates are trusted If certificates that used to work suddenly throw authority warnings, re-running mkcert -install is the first thing to try; it’s idempotent and safe to run repeatedly. Related Links - mkcert on GitHub - Supported root stores (official README) - mkcert releases & pre-built binaries - Homebrew formula

  3. Afterlight: the ghost you leave in the machine, sealed on your own laptop This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine What I Built When someone dies, their family inherits a ghost: accounts nobody can find, subscriptions that keep billing, a laptop no one can unlock, thousands of photos on a drive no one knew existed. Almost nobody leaves a map. Afterlight is that map. It is a local-first digital estate planner. A language model running on your own laptop interviews you, one plain question at a time, and turns your answers into a letter of instruction for the people you love: where things are, who to call, what to cancel, what you want. The letter is encrypted, and the key is split into five printable cards. Any three unlock it. Nothing ever touches a server. I took "ghost in the machine" literally, and kindly. Día de los Muertos is about keeping the dead present through memory and care. Afterlight is the practical side of that: the last thing you do so that your family's grief is not also a scavenger hunt. It is not a chatbot that impersonates the dead. It never pretends to be anyone. What it does: - Interviews you. A local model asks natural follow-ups, but a state machine decides which topics are covered, so a small model stays on track. - Refuses secrets. If you paste a password, card number, or seed phrase, a guard blocks it before it reaches the model or the disk. The letter says where things are ("password manager, emergency kit in the blue folder"), never what they are. - Writes the letter from facts. Every fact comes from a validated record, not from model free text. The model only helps with personal messages, and you approve everything before sealing. - Seals with open standards. age encryption, with the key split by SLIP-39 into 5 cards, any 3 of which unlock it. - Recovers without me. The result opens with the stock age tool, so the family does not need Afterlight at all. I confirmed this: recovery opens with the stock age binary, no Afterlight code involved. Demo {% embed youtu.be %} Code {% embed hendrahend/afterlight %} How I Built It The central design choice is a hard split between what the model does and what plain code does. !Afterlight create flow !Afterlight recover flow Purple boxes are where the open-weight model works. Everything else is plain, testable code. The model: gemma3:4b (2.5 GB), served through Ollama on a Windows laptop with no GPU. The backend speaks an OpenAI-compatible API, and the model name lives in a config file, not in the code. I compared one model — gemma3:4b produced valid JSON on 5 of 5 answers at about 18 tokens/s, which was enough to move forward without a GPU. The interview: a state machine owns the checklist (accounts, money, devices, people, wishes). The model rephrases each question naturally and extracts answers into a JSON schema using constrained output. Pydantic validates the result. If the model fails, static fallback questions keep the interview going. A small model plus a strict scaffold turned out to be more reliable than a big model improvising. The guard: regex and entropy checks (Luhn for card numbers, seed-phrase patterns, high-entropy tokens) run on every answer before it goes anywhere. The seal: a random 128-bit secret becomes the age passphrase, and the same secret is split with SLIP-39 (shamir-mnemonic, Trezor's reference implementation) into 3-of-5 word shares with checksums, printed as cards with a QR code. A RECOVERY.txt in the package explains, in plain language, how to open everything with only age and any SLIP-39 tool. <!-- TODO: afterlight-recover-flow.png — upload and paste the URL --> _Recover flow diagram coming once I capture the screenshots._ Recovery needs no model at all, only open tools. Tests: 163 tests. Seal and recover round-trip for every 3-of-5 combination, fail correctly with only 2 shares, catch a single checksum typo in a share word, reject guard samples (API keys, card numbers, seed phrases), and a test fails on any non-loopback network connection. I wrote the spec first in AGENTS.md and built the code with opencode following it. I decided the architecture and the hard rules up front (local-first, no plaintext on disk, guard every answer, no non-loopback network); the agent implemented to that plan rather than inventing its own. Why Does Open Innovation Matter? Privacy is the precondition, not a feature. This is the most sensitive data a person owns: accounts, money, family, wishes. With a closed API, every answer in the interview would travel to someone else's server. With an open-weight model on my own laptop, nothing leaves. You do not have to take my word for it: the demo runs with Wi-Fi off, and the test suite fails if the code opens a non-local connection. This must outlive me. A digital legacy tool that depends on a company is a promise that expires when the company does. Afterlight's output uses open standards with independent implementations, age and SLIP-39. In thirty years, your family needs a copy of age and the instructions in RECOVERY.txt. They do not need this project, and they do not need me. The model is swappable. Changing the model is one line of config. That is what lets the same tool run on a modest laptop today and on whatever small model is best next year. It costs nothing to run, which matters for something people should do once and not pay a subscription to keep safe. The honest tradeoff: a small local model is not as capable as a frontier model, so it cannot be trusted to improvise. That pushed me to give it a narrow job inside a deterministic structure, and I think the tool is safer for it. The Spirit of It The first time I ran the interview on my own life, the questions were simple but the answers were not. "Where are your accounts?" — I could answer that. "Who should get the photo drive no one else knows about?" — I had to decide, and deciding meant admitting there was something to decide. The guard is the moment I respect most: I pasted a real-looking API key into the test on purpose, and it refused to seal. It would rather be a pain in the moment than a secret leaked in a letter. And when three cards opened the letter and two did not, the 3-of-5 math stopped being a theorem and became a promise I could actually keep for my family.

  4. @sahota_ad @asciidiego No it's really easy. There are scripts that even do both steps in one like mkcert filosottile/mkcert Browsers should already have eMudhra CA certs in their CRLs so I'd expect if you try it right now it would not work.

    1 like · 38 views
  5. YouTube · · YouTube description · The AI Toolbox · FiloSottile/age

    Are your passwords in Git in plain text? SOPS encrypts them SOPS (Secrets OPerationS) is an open-source command-line tool for encrypting secrets in config files: it encrypts the values in YAML, JSON, ENV and INI files (and whole binary files) with age, PGP, AWS KMS, GCP KMS, Azure Key Vault, HuaweiCloud KMS or HashiCorp Vault and OpenBao, so the secrets can sit in Git next to your config. The names stay readable and only the values are encrypted, so diffs stay useful. It's MPL 2.0 licensed and a CNCF Sandbox project. In this video: - What SOPS is and how it works (one data key per file, locked for each key you choose; sops edit decrypts into your editor and encrypts again when you exit) - 3 real uses: commit encrypted secrets to Git, one .sops.yaml rules file for dev and prod keys, and passing secrets to an app with exec-env - The catch: you manage the keys, losing every key means losing the data, names stay readable, and what to do if a key leaks - Who it's for, an alternative, and how to try it Three real uses: 1. Commit secrets to Git: each value is encrypted with AES-256-GCM (AES256_GCM), so a diff points to the value that changed (the sops: block's date and checksum change too). With a .gitattributes entry and git config diff.sopsdiffer.textconv "sops decrypt", git diff can show decrypted diffs to anyone who holds a key. 2. One rules file: a .sops.yaml at the repo root holds creation_rules, where path_regex picks the keys for each file, for example one age key for development files and another for production. The first matching rule wins. 3. Pass secrets to an app: sops exec-env puts the decrypted values in one child process's environment, never written to disk; sops exec-file hands the app a FIFO or a temporary file instead. Also in the docs: --encrypted-regex to encrypt only the data and stringData values of a Kubernetes secrets file, key groups with Shamir's Secret Sharing (for example, keys from 2 of 3 groups needed to decrypt), sops updatekeys and sops rotate, and an optional audit log to PostgreSQL. The catch: SOPS doesn't create or store your master keys. You bring age or PGP keys, a cloud key service (AWS KMS, Google Cloud KMS, Azure Key Vault and HuaweiCloud KMS are paid services of those cloud providers) or HashiCorp Vault or OpenBao. A file can be decrypted as long as one of its keys still works, so if you lose every one, the data can't be recovered: keep a backup key (the docs describe a spare PGP key kept securely for emergency decryption). Only values are encrypted: names and the file's structure stay readable, and the docs advise keeping encrypted files reasonably private. If a key leaks, remove it from .sops.yaml, run sops updatekeys, then sops rotate for a new data key, and only then change the passwords themselves. YAML anchors and top-level arrays aren't supported, and the key service connection has no authentication or encryption of its own (the docs suggest an SSH tunnel). There's no web interface or central secrets server: it's a command-line tool. Try it (with dummy values): Download a binary for your platform from github.com/getsops/sops/releases age-keygen -o key.txt (age-keygen comes with age, its own tool) sops encrypt --age "$(age-keygen -y key.txt)" --output test.enc.yaml test.yaml export SOPS_AGE_KEY_FILE=key.txt sops decrypt test.enc.yaml Back up key.txt: it's your private key. Links: Repo: getsops/sops Docs: getsops.io Installation: getsops.io age keys: getsops.io .sops.yaml rules: getsops.io Key management and rotation: getsops.io exec-env and exec-file: getsops.io Security and threat model: getsops.io Licence (MPL 2.0): github.com/getsops/sops/blob/main/LICENSE age: FiloSottile/age Alternative: Infisical, Infisical/infisical Facts checked 2026-10-20 (SOPS v3.13.3, released 2026-07-23; 23,455 GitHub stars). Started at Mozilla in 2015, a CNCF Sandbox project since 2023. An open-source option to consider, not an endorsement. Not affiliated with the SOPS project, the CNCF, Mozilla or Infisical. Narration: AI voice. #SOPS #SecretsManagement #DevOps Chapters 0:00 Intro 0:14 The fix 0:27 How it works 0:42 Three real uses 1:01 The catch 1:25 Who it's for 1:35 Try it

    11 views
  6. Claude Traced the NIST Curve Seeds to a 1997 Clock and lrand48. Nothing to Rotate on P-256 - Book: System Design Pocket Guide: Interviews - The series: Pocket Guides for Developers — 8 short books on agents, RAG, prompts, observability, events, databases and system design — the whole series - My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools - Me: xgabriel.com | GitHub --- The seeds behind P-256, the curve under every ES256 signature on a JWT, were not the hash of a secret NSA sentence. According to Anthropic's write-up from October 16, they came out of the C library's lrand48 random-number generator, "seeded with a Unix timestamp", on dates between May 1997 and April 1998. Anthropic says an internal research model worked that out "in under half an hour." The cryptographer who ran a three-year-old bounty on the question, Filippo Valsorda, wrote the same day that the bounty had been claimed, and that he "reimplemented the algorithm in Go to verify the claim." Before you go looking for something to patch: Anthropic's own post says "There is no action to be taken or things to do differently." What the story does give you is a settled argument from the late 1990s, and a good reason to check what mints your session tokens. The 1990s riddle When NIST standardised ECDSA in FIPS 186-2 in 2000, the curves P-192 through P-521 were each derived from a seed. Anthropic's post says those seeds "were provided by the NSA with no explanation or justification." The best-known account was that they were a hash of a humorous passphrase, and nobody could find the passphrase. That gap fed suspicion. If a curve's maker can pick its seed freely, they can, in theory, keep trying seeds until a curve has a property only they know about. Anthropic notes people have long wondered whether the seeds "may have been chosen to have deliberate backdoors in them." Nobody had evidence of one, as BleepingComputer pointed out in 2023, but nobody could rule it out either. So in 2023 Valsorda and a group of cryptographers put up $12,288 for the original sentences, tripled to $36,864 if the winner gave it to charity. What Anthropic says Claude found The answer was not a sentence at all. Per Anthropic, "Claude guessed the software used a pseudorandom number generator (PRNG) that shipped with 1990s C libraries," then recovered that generator's internal state from the published seeds, which the post calls "a textbook lattice problem." The details from the post: - The P-192, P-224, P-256, P-384 and P-521 seeds are lrand48 output, each run seeded with a Unix timestamp. P-256's run decodes to August 1997. - Four binary-curve seeds (B-233, B-283, B-409, B-571) fit the same scheme with a clock that appears to have been halved. - "For P-256, the published seed is candidate 1842, but candidate 876 of the same run also gives a prime-order curve." Why 876 was skipped is unknown. - The base point for P-192 and five ANSI X9.62 example curves came from another generator, FreeLIP's, with small integer seeds. Anthropic names lrand48; Valsorda's post says drand48. Both belong to the same POSIX family, which generates numbers "using a linear congruential algorithm and 48-bit integer arithmetic." Same engine, different output format. !An old 1990s desk clock whose gears feed a ribbon of tiles into a smooth elliptic curve, drawn as an editorial illustration The seeds came from a clock and a 48-bit generator, not a hidden sentence. Anthropic published two Python scripts that reproduce the seeds and selected base points, dedicated to the public domain under CC0. The team claimed the bounty and chose to donate it to the Internet Security Research Group, the non-profit behind Let's Encrypt, which tripled it to $36,864, according to Valsorda. Why "no backdoor" is now the strong reading Valsorda's post makes the argument in numbers. A 2017 idea from Bernstein and Lange needed roughly 70 bits of freedom in choosing seeds to aim at a class of weak curves. With timestamps and a generator, Valsorda writes that even if the NSA could pick any timestamp in 1997–98 and any of the first 16 prime-order candidates, "they would have had barely 30 bits of freedom." He says the findings "completely rule out the technique described by Bernstein and Lange." Anthropic's phrasing is more careful: the findings make a backdoor "much less plausible." And the post is explicit about scope: "This is not a cryptographic break, new attack, or weakness in the ECDSA curves." Valsorda goes further. He says this "nicely completes the 'rehabilitation arc' of NIST elliptic curve cryptography" and, given modern deterministic signing and verified implementations, calls the NIST curves ones "which I would now personally recommend over Curve25519/Ed25519/X25519." What changes in your code For P-256 itself: nothing. Don't rotate keys, don't swap curves because of this. Anthropic says so in as many words. The useful lesson is the generator. A 1997 program seeded a non-cryptographic PRNG with the clock, and decades later its output could be traced back to the second it ran. POSIX says the drand48 family "should be avoided whenever non-trivial requirements (including safety) have to be fulfilled." Python's random docs and MDN's Math.random() page carry the same warning: not for security. If you generate session IDs, reset tokens, API keys or invite codes, find out what produces them. git grep gets you a list of places to read: git grep -nE \ -e 'srand(48)?\(' -e '[dlm]rand48' \ -e 'Math\.random' -e '"math/rand' \ -e '^[[:space:]]*(import random|from random import)' The last two patterns catch Go files importing math/rand and Python files importing random, even when nothing ever calls a seed function. A hit is not a bug. Shuffling a test fixture with Math.random() is fine. A hit that ends up in a token, a password or a URL someone shouldn't guess is the one to fix. !A die split open to reveal a ticking clock face inside, with a magnifying glass hovering over it, as a flat editorial illustration A PRNG seeded from the time is only as secret as the time it ran. The fix is the operating system's cryptographic generator, which every mainstream runtime exposes. In Python, the secrets module: import secrets token = secrets.token_urlsafe(32) In Node.js, crypto.randomBytes: import { randomBytes } from "node:crypto"; const token = randomBytes(32).toString("base64url"); In Go, crypto/rand, not math/rand: import ( "crypto/rand" "encoding/hex" ) func newToken() (string, error) { b := make([]byte, 32) if _, err := rand.Read(b); err != nil { return "", err } return hex.EncodeToString(b), nil } In the browser, MDN points to crypto.getRandomValues(). What's still open, and what the AI part means The riddle isn't fully closed. Anthropic writes that "the fifth binary seed, B-163, fits nothing Claude has tried and remains unexplained," and that "we don't know how the base points for P-224, P-256, P-384, and P-521 were generated." Valsorda adds that of two extra selection criteria, one "still escapes us." On the AI side, be precise about what is public. Anthropic doesn't name the model beyond "an internal research model," and the half-hour figure is its own account of an internal run. What outsiders can check is the result, and that has been checked: the scripts are public, and Valsorda's Go reimplementation is on GitHub. A question that had stood since the late 1990s fell to a guess about old C libraries plus a standard lattice technique, and a human expert confirmed it in code within a day. I haven't run either script myself. If you have, or if you went looking through your own repo for Math.random() tokens after reading this, tell me what turned up in the comments. --- If this was useful I build Hermes IDE, a free, source-available IDE (BSL 1.1) for macOS, Windows and Linux that runs Claude Code, Codex and other coding agents side by side, each task on its own branch and worktree. If you want an agent to work through that git grep list without touching your main checkout, download it or read the source on GitHub. It isn't affiliated with Anthropic or any agent vendor. System design interviews keep coming back to the same small decisions: how you mint short links, IDs and session tokens, and what breaks if someone can predict them. The System Design Pocket Guide: Interviews walks through 15 real designs step by step, trade-offs included, so you can reason about those choices out loud. It's one of 8 short books in the Pocket Guides for Developers series, covering agents, RAG, prompts, observability, events, databases and system design. ![System Design Pocket Guide: Interviews — 15 Real System Designs, Step by Step](amazon.com)

  7. Cryptography Dispatches: The NIST Elliptic Curves Seeds Bounty Has Been Claimed The NIST Elliptic Curves Seeds Bounty Has Been Claimed We now know how the seeds of the NIST elliptic curves were generated: they’re not the hash of some saucy sentence, but the output of drand48 seeded with the time, which was indeed in 1997–98. John Wood, Henry de Valence, Ava Howell, Zack Voase, Lucy Sweet, Amir Omidi, Paul Crowley, Iain McGinniss, Nicholas Carlini, and Steve Weis from Anthropic solved the riddle and on October 15th, 2026, at 01:07:51 UTC, claimed the full bounty I announced three years ago. They chose to donate the prize to ISRG, the non-profit that operates Let’s Encrypt, tripling its value to $36,864 (36 Ki$). Thank you to Amir Omidi, Chris Palmer, Colm MacCárthaigh, David Adrian, David Anderson, Jeff Hodges, Matt Green, Matthew McPherrin, Paul Kehrer, Ryan Sleevi, and Soatok for contributing to the bounty. This helps fill out a page of cryptographic history, and reinforces our confidence in these critical cryptographic primitives. The NIST elliptic curves (P-192, P-224, P-256, P-384, and P-521) were published by NIST in FIPS 186-2 in 2000. They were generated at random according to ANSI X9.62 by taking an arbitrary seed, hashing it with SHA-1, and using the output to derive some of the parameters. Until this week, we had no idea how those arbitrary seeds were picked. The lore was that Dr. Jerry Solinas, who passed away in early 2023, generated them in 1997 by hashing some English sentences that he later forgot. You can read more in this article by Steve Weis or in the original bounty announcement. Turns out memory can play tricks on everyone: we now know they were instead generated with the POSIX-standard drand48 random number generator. The algorithm is as simple as passing the then-current UNIX timestamp to srand48() and then producing one byte at a time with drand48. Each sequence of 20 bytes is tried as a seed following ANSI X9.62 and rejected if the resulting curve is not valid. Some timestamps are used to generate multiple curves, by continuing to try seeds after accepting the first one. I reimplemented the algorithm in Go to verify the claim. Read more in Anthropic's writeup. There are two additional undocumented criteria beyond the ANSI X9.62 ones, one fairly clear and one that still escapes us. If the bit length of the order n of the resulting curve is more than the bit length of the base field p of the curve, the seed is rejected. (The condition is not the stricter n < p, because prime239v2 has p < n < 2²³⁹.) This leaves us with roughly twice as many valid seeds as were published. We explored a number of explanations for this last bit, and found no good fit. Maybe the same RNG was used to validate seeds, consuming RNG output and skipping some potential candidates, although the “gaps” are not regular. Maybe there was just a bug in one of the algorithms that returned the wrong result half the time; these calculations, which we can now do with off-the-shelf software in minutes, were still very much state-of-the-art in 1997. srand48(863711343) [1997-05-15 15:49:03 +0000 UTC]: accepted 36th seed 25e5[...]: not published accepted 1562nd seed d09b[...]: not published accepted 2185th seed e43b[...]: prime239v1 accepted 2320th seed e8b4[...]: prime239v2 accepted 2491st seed 1256[...]: not published accepted 2682nd seed d2c1[...]: not published accepted 2863rd seed 3a70[...]: not published accepted 3048th seed 7d73[...]: prime239v3 srand48(863966734) [1997-05-18 14:45:34 +0000 UTC]: accepted 139th seed 3045[...]: P-192 a.k.a. prime192v1 accepted 2198th seed 692d[...]: not published accepted 5228th seed c469[...]: prime192v3 accepted 5405th seed 3ad1[...]: not published accepted 6013th seed 31a9[...]: prime192v2 srand48(871002724) [1997-08-08 01:12:04 +0000 UTC]: accepted 1136th seed d09e[...]: P-521 srand48(871696354) [1997-08-16 01:52:34 +0000 UTC]: accepted 876th seed 50c7[...]: not published accepted 1842nd seed c49d[...]: P-256 a.k.a. prime256v1 srand48(872952608) [1997-08-30 14:50:08 +0000 UTC]: accepted 2688th seed a335[...]: P-384 srand48(891607927) [1998-04-03 12:52:07 +0000 UTC]: accepted 777th seed d007[...]: not published accepted 1485th seed 18cf[...]: not published accepted 5736th seed 3c17[...]: not published accepted 7026th seed bd71[...]: P-224 What does this mean for the security of elliptic curve cryptography based on the NIST curves? Well, even before this discovery there were no serious concerns among practitioners. In Section 3.1 of their 2015 paper “A riddle wrapped in an enigma,” Koblitz and Menezes make a convincing argument that it’s implausible that the NSA could have selected a seed to exploit a weakness that escaped more than 15 (now 25) years of cryptanalysis. However, as reported in a later version of that paper, Daniel Bernstein and Tanja Lange described to Koblitz and Menezes in 2017 a technique that could have exploited 70 bits of freedom in selection of the seed to target a hypothetical class of 2⁶¹ weak prime-order curves. (Bernstein is the author of a competing elliptic curve design, Curve25519.) This contributed to enduring conspiracy theories, which had significant appeal among the non-specialist public (although many have since moved on to other, adjacent, conspiracy theories). All this speculation harmed confidence in robust cryptographic systems and was part of my motivation for the bounty. This week’s findings completely rule out the technique described by Bernstein and Lange. Even if the NSA had been free to pick any timestamp in 1997–98 and any of the first 16 prime-order candidates (which generously accounts for the unexplained rejections), they would have had barely 30 bits of freedom. Not enough to intentionally target a hypothetical small class of weak curves, not enough to embed any kind of NOBUS backdoor. Along with deterministic and hedged ECDSA signing algorithms, formally verified field implementations, and the 2015 complete addition formulas by Renes, Costello, and Batina, this nicely completes the “rehabilitation arc” of NIST elliptic curve cryptography, which I would now personally recommend over Curve25519/Ed25519/X25519. Just in time for them to be retired in favor of post-quantum signatures. P.S. The Anthropic team also figured out how the seeds of the NIST B-curves (the ones over binary fields) were generated, but no one uses those, so who cares. The picture In a FamilyMart in Taiwan I found this delightful dice set. A full roll carries log₂(6²⁰) ≈ 51.7 bits of entropy. Rolling them twice can make a pretty robust cryptographic key! I thought it would be funny to label them as Geomys FIPS 140-3 Entropy Sources (which of course they are not, though we do have one of those) and hand them out as swag. However, I found no way to order them online, so I simply visited over a dozen FamilyMarts and brought home 50 packs. Speaking of swag, I am 100% making stickers with the srand48() seeds, and t-shirts for the Anthropic team and the contributors to the bounty. I accept suggestions for other seed-based swag. If you want to catch some, follow me on Bluesky at @filippo.abyssdomain.expert or on Mastodon at @filippo@abyssdomain.expert. Read more: Did you like this? There is no tracking, so reply to let me know! My snail mail address is 9450 SW Gemini Dr #52960, Beaverton, OR 97008 and I enjoy postcards 📮 You can narrow your topics to only cryptography or only open source maintenance. Do you want me to write more? You can sign up to pay $7/issue (max. 2 per month). My brain's reward function is easily tricked. reimplemented the algorithm in Go: github.com/FiloSottile/mostly-harmless/blob/main/… formally verified field implementations: mit-plv/fiat-crypto

  8. Firefox Certificate Handling: HTTPS Errors, Self-Signed Certs, and Corporate PKI SSL/TLS certificates are how HTTPS works — but Firefox's certificate handling has details that matter to developers and security-conscious users. This guide covers what Firefox checks, what errors mean, and how to work with certificates in development environments. What Firefox Checks When Loading HTTPS Sites Firefox validates several things for every HTTPS connection: 1. Certificate chain: the site's cert must chain up to a trusted root CA 2. Expiry: cert must not be expired 3. Hostname match: cert must match the domain being visited (Common Name or Subject Alternative Names) 4. Revocation: cert must not be on OCSP revocation lists (Firefox uses soft-fail by default) 5. Algorithm: SHA-1 certs are rejected; minimum 2048-bit RSA keys The Firefox Certificate Store Firefox maintains its own certificate store, independent of the OS. This is one area where Firefox differs fundamentally from Chrome/Edge on Windows, which use the Windows certificate store. Consequences: - Corporate-issued root CAs added via Windows Group Policy don't automatically appear in Firefox - Enterprise MITM proxies (for traffic inspection) must explicitly add their CA to Firefox - Security tools that inject a CA certificate via the OS won't affect Firefox To view Firefox's certificate store: Settings → Privacy & Security → Certificates → View Certificates Three tabs: - Authorities: trusted root CAs (Mozilla's root store + any you've added) - Servers: manually-added exceptions for specific sites - People: client certificates (rarely used by most people) Common Certificate Errors SEC_ERROR_EXPIRED_CERTIFICATE: The cert's notAfter date has passed. Most Let's Encrypt certs expire every 90 days — usually this means auto-renewal failed. SEC_ERROR_UNKNOWN_ISSUER: The cert's signing CA isn't in Firefox's trust store. Common in development (self-signed certs) and corporate proxies. SSL_ERROR_BAD_CERT_DOMAIN: The hostname doesn't match the cert. The cert might cover www.example.com but you navigated to example.com (or vice versa), or a CDN cert doesn't include your domain. MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED: Usually DigiCert or similar CA's extended validation issue. SEC_ERROR_OCSP_INVALID_SIGNING_CERT: OCSP stapling misconfiguration on the server. Working With Self-Signed Certs in Development For localhost or internal dev environments: Option 1: mkcert (recommended) mkcert is a tool that creates a local CA and installs it into your system and Firefox trust store: brew install mkcert mkcert -install # adds CA to Firefox, system, etc. mkcert localhost 127.0.0.1 ::1 # creates localhost+2.pem and localhost+2-key.pem This eliminates cert warnings for all future local dev without manual exceptions. Option 2: Add a temporary exception If you just need to proceed past the error once: on the error page click "Advanced" → "Accept the Risk and Continue". This adds a permanent server exception to Firefox's cert store (visible under View Certificates → Servers). Option 3: Use HTTP for local dev http://localhost doesn't require any certs. Firefox (unlike Chrome) doesn't force HTTPS for localhost. For local API servers, plain HTTP often works fine. Importing a Corporate Root CA If your company uses a MITM proxy or internal PKI: 1. Settings → Privacy & Security → Certificates → View Certificates → Authorities → Import 2. Select the .crt or .pem file your IT team provided 3. Check "Trust this CA to identify websites" → OK Firefox also has a setting to use OS certificate stores: security.enterprise_roots.enabled in about:config. Setting this to true makes Firefox honor root CAs added via the OS (Windows, macOS, Linux NSS), which is useful in enterprise environments. Client Certificates For mutual TLS (mTLS) where the server requires the browser to present a certificate: Settings → Privacy & Security → Certificates → View Certificates → Your Certificates → Import Firefox will prompt you to select the appropriate client cert when a server requests it. Set "When a server requests my personal certificate" to "Select one automatically" if you only have one cert, or "Ask every time" if you have multiple. Checking a Site's Certificate Click the padlock icon (or the lock in the URL bar) → Connection Secure → More Information → Security tab → View Certificate. This shows: - Issued to / Issued by - Serial Number - Validity period - SHA-256 fingerprint - Subject Alternative Names (the domains the cert covers) - Signature algorithm For developers debugging cert issues, the Security tab in DevTools (F12) also shows certificate chain info when you select a network request. HSTS (HTTP Strict Transport Security) HSTS tells browsers "only connect to this domain over HTTPS, and reject any HTTP connections." Sites set this via the Strict-Transport-Security response header. Firefox caches HSTS settings. To clear a site's HSTS status: Settings → Privacy & Security → Cookies and Site Data → Clear Data, or access about:config and search for the domain's HSTS entry (there's no built-in UI — use about:config → search security.HSTS). Firefox also ships with a preloaded HSTS list (domains that have asked to be HSTS-preloaded). For localhost testing, Firefox respects localhost. (with trailing dot) as a signal to bypass HSTS. Certificate Transparency Since Chrome and Safari required it first, most CAs now log all certificates to public CT logs. Firefox doesn't enforce CT requirements (as of 2024), but the infrastructure means every cert issued by a major CA is publicly logged and auditable at crt.sh. If you want to see what certs have been issued for your domain: https://crt.sh/?q=yourdomain.com about:config Certificate Settings Relevant preferences in about:config: | Preference | Default | Notes | |------------|---------|-------| | security.OCSP.enabled | 1 | 0 = disable OCSP, 1 = soft-fail, 2 = hard-fail | | security.enterprise_roots.enabled | false | Import OS root CAs | | security.tls.version.min | 3 | TLS 1.2 minimum (3=TLS 1.2) | | security.ssl.require_safe_negotiation | false | Reject non-RFC-5746 handshakes | | security.cert_pinning.enforcement_level | 1 | Certificate pinning level | Most users should leave these at defaults. The only common adjustment is security.enterprise_roots.enabled for corporate environments.

  9. Written by Mythos 5.1 based on filippo.io, FiloSottile/typage, the C2SP spec, and the Wycheproof test vectors. Reviewed by Astra and then by me, line by line. I had to prompt it to make the API more idiomatic, and otherwise do truly minimal manual changes.

    15 likes
  10. Cobblestone-128 chunked (aka streaming) encryption in TypeScript for Node.js 22+, Bun, Deno, and all recent browsers. One-shot, transform stream, and random access decryption APIs. Uses the Web Crypto API for AES-GCM, with fallback on the noble cryptography libraries.

    40 likes · 5 reposts
Trending awards, every completed day and week
Gold
101st place finishes
Silver
72nd place finishes
Bronze
83rd place finishes
Awarded repositories
3Owned by FiloSottile now

Repositories

Ordered by gold, then silver, then bronze.

  1. mkcertBest: 1st by stars, 3,886 stars833
  2. HeartbleedBest: 1st by stars, 662 stars134
  3. ageBest: 1st by stars, 927 stars111

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.