logo

OSS Roundup: October 2026

Author: Andrew Porter

Published: 10/28/2026

-

Four pull requests across three projects, the problems behind them, and a few places where you can help us get them over the line.

Roundup

We sent four pull requests this month, fixing two ESP32 NATS bugs and bringing a stale Mailslurper fork back in sync while backporting its fixes to the upstream.

This Month at a Glance

ProjectWhat we sentWho it helpsStatus
espidf-nats#26 (mTLS client certs)ESP32 devices on a NATS server with verify: trueOpen
espidf-nats#28 (TLS socket leak)Anyone using TLS with cert verification on ESP-IDFOpen
mailslurper#193 (UI first-load race)Anyone opening the web UI on a fresh browserOpen
ory/mailslurper#1 (fork upstream sync)Ory Quickstart usersOpen

Why Now?

For a while, CHaaS ran on a handful of local patches to libraries we depend on. That’s a perfectly normal place to be while a product is still finding its feet, but it’s not where we want to stay. Now that our user service is live and in production, we’re paying that debt back - and these are our first contributions since launch. We’re excited to contribute back to the community where we can and we have some additional upcoming projects to continue that work.

Project 1: espidf-nats

What it is: a NATS client library for ESP-IDF, by Debashish Sahu (@debsahu) that saved us weeks of time when we needed an embedded NATS.io client. Even in an AI-enabled shop this was an enormous head start on delivering a successful project. At 315Concepts we use this as part of our CHaaS project to ensure that our devices have a stable library for talking to the high-performance messaging fabric that backs the entire product experience, an understandably critical part of the architecture! You never want to find issues in critical parts of your stack but we’re excited to be helping get these issues resolved not just for ourselves but for anyone else trying to do the same stuff we are.

Fix A: mTLS client certificates weren’t being sent

PRdebsahu/espidf-nats#26
Issue#27
Touchesnats_client.h, tcp_transport.h
SymptomYou configure a client certificate and key, the TLS upgrade reports success, and then the very first read fails on every connection - because the server rejected you.
Causenats_tls_config_t accepts and validates client_cert and client_key, but upgrade_to_tls() never hands them to mbedTLS. The handshake goes out with no client identity, so a server running verify: true closes the door.
FixAfter the CA chain is parsed, we parse the cert and key and attach them with mbedtls_ssl_conf_own_cert(). If anything fails, we log the mbedTLS error and bail out cleanly. Configs without a client cert behave exactly as before.

Results on our bench (ESP32-C6, ESP-IDF v6.0.1, mbedTLS 4.0):

OutcomeFix offFix on
Tests passed0 of 1717 of 17

Fix B: a socket leak after a failed TLS upgrade

PRdebsahu/espidf-nats#28
Issue#29
Touchesnats_client.h (NATS::disconnect())
SymptomA device that can’t verify its server’s certificate retries forever, and after 16 attempts everything on the device that needs a socket stops working - OTA, MQTT, HTTP, all of it - until a reboot.
Causedisconnect() returns early when connected is false, and connected is only set after INFO and CONNECT succeed. After a failed TLS upgrade it’s still false, so ::close(sockfd) never runs. Each retry orphans one LWIP socket until CONFIG_LWIP_MAX_ACTIVE_TCP (default 16) runs out.
FixRemove the early return so cleanup always runs, and remember was_connected so the on_disconnect callback still only fires when it did before.

Results on our bench (ESP32-C6, ESP-IDF v6.0.1, mbedTLS 4.0):

SocketFix offFix on
First 16 attemptsclimb from 48 to 63stay on 48
Attempts 17-20fail with ENOBUFSsucceed in reusing the socket

A note on severity. We labelled the PR “critical” because the failure is unrecoverable without a power cycle and takes the whole device’s networking with it. Scored with CVSS 3.1 it comes out at 5.9 (Medium), because it needs fairly specific failure types to trigger. Maintainers know their users best, so please rate it however you see fit. The confirmed trigger is a host verification failure, such as a SAN mismatch or a botched certificate rotation. No attacker is needed, so a routine (and trusted) misconfiguration is all that’s needed to take the device offline - which is why we rate it critical operationally.

If you’re affected today:

  • Make sure the certificate matches the host or IP you connect to, and rehearse rotations before deploying them
  • Watch your free socket count, and restart after repeated socket() failures
  • Please don’t set skip_cert_verification = true as a workaround. It stops this leak but also turns off server authentication.

Reproduce it yourself

Both PRs link to demo branches under SwissArmyBud/espidf-nats with a Dockerized NATS server (make nats-tls), a flag to toggle each fix, and the raw logs. Flash it once with the fix off and once with it on, and compare.

Project 2: Mailslurper

What it is: a small SMTP server with a web UI that catches outgoing email, which is handy for checking that your auth flows really are sending what you think they are. It’s part of FiMOr’s debug module, which is how we ended up here. When we were putting that project together we noticed the copy of Mailslurper used by the Ory Quickstart had drifted well behind upstream but it carried some thoughtful Ory and non-Ory changes. We wanted to help out and slap a new coat of paint on the fork, but the internal APIs had moved enough that a plain merge wouldn’t produce working software. So we ended up taking two different approaches and tried to make each one useful to someone other than us.

Step 1: bring the Ory fork up to date

PRory/mailslurper#1
Branchaporter/261027-merge-upstream into master

We merged mailslurper/master and then re-applied Ory’s own custom behavior on top, aiming for the smallest change that keeps the Kratos Quickstart working. The merge brings along Go modules, a configurable config-file location, new SMTP command executors, storage updates, proxy support (aha!), and Docker packaging work. The Ory-specific changes we preserved are the settings-service behavior, the Dockerfile-smtps build, and the MySQL LONGTEXT change for attachments over 64 KB.

We used Claude Code to read the compact Ory changes and re-implement them against the new APIs. We QA’d the results and a bot reviewer also left a number of comments, which we’ve replied to on the PR.

Step 2: send the non-Ory fix back to upstream

PRmailslurper/mailslurper#193
TouchesSettingsService.js, HomeController.js, AdminController.js, www.go
SymptomOn a browser with empty localStorage, the first page load can throw on JSON.parse(undefined) or build a bad service URL.
FixA new ensureServiceSettings() promise that returns immediately if settings are stored, and otherwise fetches /servicesettings and stores that result before resolving. Both controllers now wait on it and nothing changes when settings already exist.

Once the Ory fork was working again, we looked at which of its changes weren’t really about Ory at all and we spotted a good one - a first-load race condition lives in the shared web UI, so anyone running upstream Mailslurper on a fresh browser will hit it. A single browser refresh fixes it, which is exactly the kind of bug that’s easy to shrug off for a long time… until now! The original fix came from Ory’s fork, so credit to Aeneas Rekkas (@aeneasr) for the approach. We isolated just that change, left every Ory-specific piece behind, and sent it to upstream as a small standalone PR, with Claude Code helping on the port, just as in Step 1.

Where You Can Help

None of this is finished until someone other than us has looked at it and the code is merged. Here are the gaps we know about, and you are welcome to help us plug some of them.

Embedded testing we haven’t done:

  • [ - ] Run PR #26 or #28 on an ESP-IDF 5.x build (mbedTLS 3.x)
  • [ - ] Try them on a chip other than the ESP32-C6
  • [ - ] Check mTLS on TLS 1.2 - all our runs negotiated TLS 1.3
  • [ - ] Try the WebSocket transport and the reconnect path under process() with the socket fix
  • [ - ] Trigger the socket leak with a TLS error other than 0x2700

Costs you nothing to star the projects. Mailslurper and espidf-nats are small projects that carry real weight for the people who use them.

Thank-Yous

Spotted something we got wrong, or have a project you think we should look at next month? Smack a comment on any of the Issues or PRs above, or find the rest of our work on GitHub.