curl security moves again

tldr: curl goes back to Hackerone.

When we announced the end of the curl bug-bounty at the end of January 2026, we simultaneously moved over and started accepting curl security reports on GitHub instead of its previous platform.

This move turns out to have been a mistake and we are now undoing that part of the decision. The reward money is still gone, there is no bug-bounty, no money for vulnerability reports, but we return to accepting and handling curl vulnerability and security reports on Hackerone. Starting March 1st 2026, this is now (again) the official place to report security problems to the curl project.

This zig-zagging is unfortunate but we do it with the best of intentions. In the curl security team we were naively thinking that since so many projects are already using this setup it should be good enough for us too since we don’t have any particular special requirements. We wrongly thought. Now I instead question how other Open Source projects can use this. It feels like an area and use case for Open Source projects that is under-focused: proper, secure and efficient vulnerability reporting without bug-bounty.

What we want from a security reporting system

To illustrate what we are looking for, I made a little list that should show that we’re not looking for overly crazy things.

  1. Incoming submissions are reports that identify security problems.
  2. The reporter needs an account on the system.
  3. Submissions start private; only accessible to the reporter and the curl security team
  4. All submissions must be disclosed and made public once dealt with. Both correct and incorrect ones. This is important. We are Open Source. Maximum transparency is key.
  5. There should be a way to discuss the problem amongst security team members, the reporter and per-report invited guests.
  6. It should be possible to post security-team-only messages that the reporter and invited guests cannot see
  7. For confirmed vulnerabilities, an advisory will be produced that the system could help facilitate
  8. If there’s a field for CVE, make it possible to provide our own. We are after all our own CNA.
  9. Closed and disclosed reports should be clearly marked as invalid/valid etc
  10. Reports should have a tagging system so that they can be marked as “AI slop” or other terms for statistical and metric reasons
  11. Abusive users should be possible to ban/block from this program
  12. Additional (customizable) requirements for the privilege of submitting reports is appreciated (rate limit, time since account creation, etc)

What’s missing in GitHub’s setup?

Here is a list of nits and missing features we fell over on GitHub that, had we figured them out ahead of time, possibly would have made us go about this a different way. This list might interest fellow maintainers having the same thoughts and ideas we had. I have provided this feedback to GitHub as well – to make sure they know.

  1. GitHub sends the whole report over email/notification with no way to disable this. SMTP and email is known for being insecure and cannot assure end to end protection. This risks leaking secrets early to the entire email chain.
  2. We can’t disclose invalid reports (and make them clearly marked as such)
  3. Per-repository default collaborators on GitHub Security Advisories is annoying to manage, as we now have to manually add the security team for each advisory or have a rather quirky workflow scripting it. https://github.com/orgs/community/discussions/63041
  4. We can’t edit the CVE number field! We are a CNA, we mint our own CVE records so this is frustrating. This adds confusion.
  5. We want to (optionally) get rid of the CVSS score + calculator in the form as we actively discourage using those in curl CVE records
  6. No CI jobs working in private forks is going to make us effectively not use such forks, but is not a big obstacle for us because of our vulnerability working process. https://github.com/orgs/community/discussions/35165
  7. No “quote” in the discussions? That looks… like an omission.
  8. We want to use GitHub’s security advisories as the report to the project, not the final advisory (as we write that ourselves) which might get confusing, as even for the confirmed ones, the project advisories (hosted elsewhere) are the official ones, not the ones on GitHub
  9. No number of advisories count is displayed next to “security” up in the tabs, like for issues and Pull requests. This makes it hard to see progress/updates.
  10. When looking at an individual advisory, there is no direct button/link to go back to the list of current advisories
  11. In an advisory, you can only “report content”, there is no direct “block user” option like for issues
  12. There is no way to add private comments for the team-only, as when discussing abuse or details not intended for the reporter or other invited persons in the issue
  13. There is a lack of short (internal) identifier or name per issue, which makes it annoying and hard to refer to specific reports when discussing them in the security team. The existing identifiers are long and hard to differentiate from each other.
  14. You quite weirdly cannot get completion help for @nick in comments to address people that were added into the advisory thanks to them being in a team you added to the issue?
  15. There are no labels, like for issues and pull requests, which makes it impossible for us to for example mark the AI slop ones or other things, for statistics, metrics and future research

Email?

Sure, we could switch to handling them all over email but that also has its set of challenges. Including:

  • Hard to keep track of the state of each current issue when a number of them are managed in parallel. Even just to see how many cases are still currently open or in need of attention.
  • Hard to publish and disclose the invalid ones, as they never cause an advisory to get written and we rather want the initial report and the full follow-up discussion published.
  • Hard to adapt to or use a reputation system beyond just the boolean “these people are banned”. I suspect that we over time need to use more crowdsourced knowledge or reputation based on how the reporters have behaved previously or in relation to other projects.

Onward and upward

Since we dropped the bounty, the inflow tsunami has dried out substantially. Perhaps partly because of our switch over to GitHub? Perhaps it just takes a while for all the sloptimists to figure out where to send the reports now and perhaps by going back to Hackerone we again open the gates for them? We just have to see what happens.

We will keep iterating and tweaking the program, the settings and the hosting providers going forward to improve. To make sure we ship a robust and secure set of products and that the team doing so can do that

Security problems?

If you suspect a security problem in curl or libcurl, report it here: https://hackerone.com/curl

The other forges don’t even try

Gitlab, Codeberg and others are GitHub alternatives and competitors, but few of them offer this kind of security reporting feature. That makes them bad alternatives or replacements for us for this particular service.

decomplexification continued

Last spring I wrote a blog post about our ongoing work in the background to gradually simplify the curl source code over time.

This is a follow-up: a status update of what we have done since then and what comes next.

In May 2025 I had just managed to get the worst function in curl down to complexity 100, and the average score of all curl production source code (179,000 lines of code) was at 20.8. We had 15 functions still scoring over 70.

Almost ten months later we have reduced the most complex function in curl from 100 to 59. Meaning that we have simplified a vast number of functions. Done by splitting them up into smaller pieces and by refactoring logic. Reviewed by humans, verified by lots of test cases, checked by analyzers and fuzzers,

The current 171,000 lines of code now has an average complexity of 15.9.

Complexity

The complexity score in this case is just the cold and raw metric reported by the pmccabe tool. I decided to use that as the absolute truth, even if of course a human could at times debate and argue about its claims. It makes it easier to just obey to the tool, and it is quite frankly doing a decent job at this so it’s not a problem.

How to simplify

In almost all cases the main problem with complex functions is that they do a lot of things in a single function – too many – where the functionality performed could or should rather be split into several smaller sub functions. In almost every case it is also immediately obvious that when splitting a function into two, three or more sub functions with smaller and more specific scopes, the code gets easier to understand and each smaller function is subsequently easier to debug and improve.

Development

I don’t know how far we can take the simplification and what the ideal average complexity score of a the curl code base might be. At some point it becomes counter-effective and making functions even smaller then just makes it harder to follow code flows and absorbing the proper context into your head.

Graphs

To illustrate our simplification journey, I decided to render graphs with a date axle starting at 2022-01-01 and ending today. Slightly over four years, representing a little under 10,000 git commits.

First, a look a the complexity of the worst scored function in curl production code over the last four years. Comparing with P90 and P99.

Identifying the worst function might not say too much about the code in general, so another check is to see how the average complexity has changed. This is calculated like this:

  • All functions get a complexity score by pmccabe
  • Each function has a number of lines

For all functions, add its function-score x function-length to a total complexity score, and in the end, divide that total complexity score on total number of lines used for all functions. Also do the same for a median score.

When 2022 started, the average was about 46 and as can be seen, it has been dwindling ever since, with a few steep drops when we have merged dedicated improvement work.

One way to complete the average and median lines to offer us a better picture of the state, is to investigate the complexity distribution through-out the source code.

This reveals that the most complex quarter of the code in 2022 has since been simplified. Back then 25% of the code scored above 60, and now all of the code is below 60.

It also shows that during 2025 we managed to clean up all the dark functions, meaning the end of 100+ complexity functions. Never to return, as the plan is at least.

Does it matter?

We don’t really know. We believe less complex code is generally good for security and code readability, but it is probably still too early for us to be able to actually measure any particular positive outcome of this work (apart from fancy graphs). Also, there are many more ways to judge code than by this complexity score alone. Like having sensible APIs both internal and external and making sure that they are properly and correctly documented etc. The fact that they all interact together and they all keep changing, makes it really hard to isolate a single factor like complexity and say that changing this alone is what makes an impact.

Additionally: maybe just the refactor itself and the attention to the functions when doing so either fix problems or introduce new problems, that is then not actually because of the change of complexity but just the mere result of eyes giving attention on that code and changing it right then.

Maybe we just need to allow several more years to pass before any change from this can be measured?

Open Source security in spite of AI

The title of my ending keynote at FOSDEM February 1, 2026.

As the last talk of the conference, at 17:00 on the Sunday lots of people had already left, and presumably a lot of the remaining people were quite tired and ready to call it a day.

Still, the 1500 seats in Janson got occupied and there was even a group of more people outside wanting to get in that had to be refused entry.

The video recording

Thanks to the awesome FOSDEM video team, the recording was made available this quickly after the presentation.

You can also get the video off FOSDEM servers.

The slides

The 59 slide PDF version.

A third medal

In January 2025 I received the European Open Source Achievement Award. The physical manifestation of that prize was a trophy made of translucent acrylic (or something similar). The blog post I above has a short video where I show it off.

In the year that passed since, we have established an organization for how do the awards going forward in the European Open Source Academy and we have arranged the creation of actual medals for the awardees.

That was the medal we gave the award winners last week at the award ceremony where I handed Greg his prize.

I was however not prepared for it, but as a direct consequence I was handed a medal this year, in recognition for the award a got last year, because now there is a medal. A retroactive medal if you wish. It felt almost like getting the award again. An honor.

The medal design

The medal is made in a shiny metal, roughly 50mm in diameter. In the middle of it is a modern version (with details inspired by PCB looks) of the Yggdrasil tree from old Norse mythology – the “World Tree”. A source of life, a sacred meeting place for gods.

In a circle around the tree are twelve stars, to visualize the EU and European connection.

On the backside, the year and the name are engraved above an EU flag, and the same circle of twelve stars is used there as a margin too, like on the front side.

The medal has a blue and white ribbon, to enable it to be draped over the head and hung from the neck.

The box is sturdy thing in dark blue velvet-like covering with European Open Source Academy printed on it next to the academy’s logo. The same motif is also in the inside of the top part of the box.

Many

I do feel overwhelmed and I acknowledge that I have receive many medals by now. I still want to document them and show them in detail to you, dear reader. To show appreciation; not to boast.