Timo Tijhof
banner
timotijhof.net
Timo Tijhof
@timotijhof.net
Dutch expat in London.

Principal Engineer at Wikimedia Foundation, QUnit project lead @qunit, jQuery Infra Team @jquery, W3C Web Perf WG.

Avatar: I look up […]

🌉 bridged from ⁂ https://fosstodon.org/@krinkle, follow @ap.brid.gy to interact
Pinned
📝 Wikimedia blog: Unifying our mobile and desktop domains

Reduced mobile response times by 20% worldwide and un-broke Google indexing.

https://techblog.wikimedia.org/2025/11/21/unifying-mobile-and-desktop-domains/

#wikimedia #mediawiki #wikipedia
Unifying our mobile and desktop domains
How we achieved 20% faster mobile response times, improved SEO, and reduced infrastructure load.
techblog.wikimedia.org
Reposted by Timo Tijhof
Google sues SerpApi for scraping the Google search results. "Google called SerpApi's "business model is parasitic," adding "SerpApi uses automated means to scrape these other services." This generates "billions of artificial requests and then copying and selling the responses. SerpApi does not […]
Original post on social.vivaldi.net
social.vivaldi.net
December 22, 2025 at 9:07 AM
Reposted by Timo Tijhof
it paints a hell of a story
December 22, 2025 at 2:26 AM
Reposted by Timo Tijhof
Excuse me? Average of 10.2 drinks per week? And that's their lowest figure on record? www.ft.com/content/0f42...

Given how averages work, and that most people in my "bubble" only have a few occasional pints... who are all these people who go into dozens?
December 22, 2025 at 12:18 AM
Reposted by Timo Tijhof
When web specs are not clear, just go to the source code
December 22, 2025 at 9:24 PM
Anna’s Archive scraped most of Spotify and has begun distributing it via bulk torrents. Metadata is published, audio coming in later drops.

With so much stuck behind subscription walls, this seems the closest thing we have to preserving our fragile digital-only culture.

It does make for an […]
Original post on fosstodon.org
fosstodon.org
December 22, 2025 at 5:05 PM
Reposted by Timo Tijhof
React just announced their new logo. Pretty bold for them, I must say
December 21, 2025 at 2:01 PM
Why Does A.I. Write Like … That?

Sam Kriss for the New York Times:

"""
According to the data, post-ChatGPT papers lean more on words like “underscore,” “highlight” and “showcase” than pre-ChatGPT papers [..] And “delve” [..] shot up by 2,700 percent.
""" […]
Original post on fosstodon.org
fosstodon.org
December 18, 2025 at 5:00 PM
Reposted by Timo Tijhof
Reposted by Timo Tijhof
GitHub Actions charging per build minute for *self-hosted-runners*? Shit's about to hit the fan lol
December 16, 2025 at 5:57 PM
Reposted by Timo Tijhof
A short snappy breakdown of some lovely attention to detail you can apply with CSS. Surprisingly high browser support too!

https://webkit.org/blog/17628/target-text-an-easy-way-to-style-text-fragments/
::target-text: An easy way to style text fragments
You’re reading a great blog post.
webkit.org
December 16, 2025 at 2:01 PM
Reposted by Timo Tijhof
December 16, 2025 at 10:10 AM
Reposted by Timo Tijhof
Just show the prompt and save us all time and resources.

https://distantprovince.by/posts/its-rude-to-show-ai-output-to-people/
It's rude to show AI output to people | Alex Martsinovich
Feeding slop is an act of war
distantprovince.by
December 11, 2025 at 4:03 PM
Theory: Firefox 1000, before Safari 100

Back in 2011 a colleague of mine theorised that Chrome would use triple digits before IE uses double digits.

https://theoreticallogic.com/2011/09/browser-releases/

Fast forward to today:

> Firefox 147
> Chrome 144
> Safari 26

I now expect Firefox and […]
Original post on fosstodon.org
fosstodon.org
December 13, 2025 at 12:52 AM
Reposted by Timo Tijhof
On this day six years ago, we learned that mr Robot curls:

https://daniel.haxx.se/blog/2019/12/10/mr-robot-curls/

Exactly three years, still this date, we found a #curl sighting in the movie Silk Road:

https://daniel.haxx.se/blog/2022/12/10/curl-sighting-silk-road/
Mr Robot curls
The Mr Robot TV series features a security expert and hacker lead character, Elliot. ## Season 4, episode 8 **Vasilis Lourdas** reported that he did a “curl sighting” in the show and very well I took a closer peek and what do we see some 37 minutes 36 seconds into episode 8 season 4… (I haven’t followed the show since at some point in season two so I cannot speak for what actually has happened in the plot up to this point. I’m only looking at and talking about what’s on the screenshots here.) Elliot writes Python. In this Python program, we can see two curl invokes, both unfortunately a blurry on the right side so it’s hard to see them exactly (the blur is really there in the source and I couldn’t see/catch a single frame without it). Fortunately, I think we get some additional clues later on in episode 10, see below. He invokes curl with `-i` to see the response header coming back but then he makes some questionable choices. The `-k` option is the short version of `--insecure`. It truly makes a HTTPS connection insecure since it completely switches off the CA cert verification. We all know no serious hacker would do that in a real world use. Perhaps the biggest problem for me is however the following `-X POST`. In itself it doesn’t have to be bad, but when taking the second shot from episode 10 into account we see that he really does combine this with the use of `-d` and thus the `-X` is totally superfluous or perhaps even wrong. The show technician who wrote this copied a bad example… The `-b` that follows is fun. That sets a specific cookie to be sent in the outgoing HTTP request. The random look of this cookie makes it smell like a session cookie of some sorts, which of course you’d rarely then hard-code it like this in a script and expect it to be of use at a later point. (Details unfold later.) ## Season 4, episode 10 Lucas Pardue followed-up with this second sighting of curl from episode 10, at about 23:24. It appears that this might be the python program from episode 8 that is now made to run on or at least with a mobile phone. I would guess this is a session logged in somewhere else. In this shot we can see the command line again from episode 8. We learn something more here. The -b option didn’t specify a cookie – because there’s no = anywhere in the argument following. It actually specified a file name. Not sure that makes anything more sensible, because it seems weird to purposely use such a long and random-looking filename to store cookies in… Here we also see that in this POST request it passes on a bank account number, a “coin address” and `amountOfCoins=3684210526.31579` to this URL: `https://buy-crypto-coin.net/purchase`, and it gets `200 OK` back from a HTTP/1.1 server. ## I tried it curl -i -k -X POST -d bankAccountNumber=8647389203882 -d coinAddress=1MbwAEKJCtPYpLPxEkUmZxwjk63nQrpbXo -d amountOfCoins=3684210526.31579 https://buy-crypto-coin.net/purchase I don’t have the cookie file so it can’t be repeated completely. What did I learn? First: OpenSSL 1.1.1 doesn’t even want to establish a TLS connection against this host and says `dh key too small`. So in order to continue this game I took to a curl built with a TLS library that didn’t complain on this silly server. Next: I learned that the server responding on this address (because there truly is a HTTPS server there) doesn’t have this host name in its certificate so `-k` is truly required to make curl speak to this host! Then finally it didn’t actually do anything fun that I could notice. How boring. It just responded with a 301 and `Location: http://www.buy-crypto-coin.net`. Notice how it redirects away from HTTPS. What’s on that site? A rather good-looking fake cryptocurrency market site. The links at the bottom all go to various NBC Universal and USA Network URLs, which I presume are the companies behind the TV series. I saved a screenshot below just in case it changes.
daniel.haxx.se
December 10, 2025 at 9:06 AM
Reposted by Timo Tijhof
DHH launches something he says is Open Source but isn't. https://world.hey.com/dhh/fizzy-is-our-fun-modern-take-on-kanban-and-we-made-it-open-source-54ac41b6

Matt Mullenweg calls it false advertising: https://ma.tt/2025/12/dhh-open-source/

All this I learned from Dries Buytaert […]
Original post on mastodon.social
mastodon.social
December 9, 2025 at 11:01 PM
Reposted by Timo Tijhof
Addressing Linux’s Missing PKI Infrastructure

"we’re starting the development of upki: a universal PKI tool. This project initially aims to close the revocation gap through the combination of a new system utility and eventual library support for common TLS/SSL libraries such as OpenSSL, GnuTLS […]
Original post on mastodon.social
mastodon.social
December 9, 2025 at 1:18 PM
Reposted by Timo Tijhof
The strangest Excel functions you'll never use https://www.makeuseof.com/strange-microsoft-excel-functions-no-one-ever-uses/ Starring "BAHTTEXT converts a number into Thai Baht words"
The strangest Excel functions you'll never use
These formulas belong in a museum.
www.makeuseof.com
December 3, 2025 at 9:10 AM
Reposted by Timo Tijhof
The package manager in GitHub Actions might be the worst package manager in use today: https://nesbitt.io/2025/12/06/github-actions-package-manager.html
GitHub Actions Has a Package Manager, and It Might Be the Worst
After putting together ecosyste-ms/package-manager-resolvers, I started wondering what dependency resolution algorithm GitHub Actions uses. When you write `uses: actions/checkout@v4` in a workflow file, you’re declaring a dependency. GitHub resolves it, downloads it, and executes it. That’s package management. So I went spelunking into the runner codebase to see how it works. What I found was concerning. Package managers are a critical part of software supply chain security. The industry has spent years hardening them after incidents like left-pad, event-stream, and countless others. Lockfiles, integrity hashes, and dependency visibility aren’t optional extras. They’re the baseline. GitHub Actions ignores all of it. Compared to mature package ecosystems: Feature | npm | Cargo | NuGet | Bundler | Go | Actions ---|---|---|---|---|---|--- Lockfile | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ Transitive pinning | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ Integrity hashes | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ Dependency tree visibility | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ Resolution specification | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ The core problem is the lack of a lockfile. Every other package manager figured this out decades ago: you declare loose constraints in a manifest, the resolver picks specific versions, and the lockfile records exactly what was chosen. GitHub Actions has no equivalent. Every run re-resolves from your workflow file, and the results can change without any modification to your code. Research from USENIX Security 2022 analyzed over 200,000 repositories and found that 99.7% execute externally developed Actions, 97% use Actions from unverified creators, and 18% run Actions with missing security updates. The researchers identified four fundamental security properties that CI/CD systems need: admittance control, execution control, code control, and access to secrets. GitHub Actions fails to provide adequate tooling for any of them. A follow-up study using static taint analysis found code injection vulnerabilities in over 4,300 workflows across 2.7 million analyzed. Nearly every GitHub Actions user is running third-party code with no verification, no lockfile, and no visibility into what that code depends on. **Mutable versions.** When you pin to `actions/checkout@v4`, that tag can move. The maintainer can push a new commit and retag. Your workflow changes silently. A lockfile would record the SHA that `@v4` resolved to, giving you reproducibility while keeping version tags readable. Instead, you have to choose: readable tags with no stability, or unreadable SHAs with no automated update path. GitHub has added mitigations. Immutable releases lock a release’s git tag after publication. Organizations can enforce SHA pinning as a policy. You can limit workflows to actions from verified creators. These help, but they only address the top-level dependency. They do nothing for transitive dependencies, which is the primary attack vector. **Invisible transitive dependencies.** SHA pinning doesn’t solve this. Composite actions resolve their own dependencies, but you can’t see or control what they pull in. When you pin an action to a SHA, you only lock the outer file. If it internally pulls `some-helper@v1` with a mutable tag, your workflow is still vulnerable. You have zero visibility into this. A lockfile would record the entire resolved tree, making transitive dependencies visible and pinnable. Research on JavaScript Actions found that 54% contain at least one security weakness, with most vulnerabilities coming from indirect dependencies. The tj-actions/changed-files incident showed how this plays out in practice: a compromised action updated its transitive dependencies to exfiltrate secrets. With a lockfile, the unexpected transitive change would have been visible in a diff. **No integrity verification.** npm records `integrity` hashes in the lockfile. Cargo records checksums in `Cargo.lock`. When you install, the package manager verifies the download matches what was recorded. Actions has nothing. You trust GitHub to give you the right code for a SHA. A lockfile with integrity hashes would let you verify that what you’re running matches what you resolved. **Re-runs aren’t reproducible.** GitHub staff have confirmed this explicitly: “if the workflow uses some actions at a version, if that version was force pushed/updated, we will be fetching the latest version there.” A failed job re-run can silently get different code than the original run. Cache interaction makes it worse: caches only save on successful jobs, so a re-run after a force-push gets different code _and_ has to rebuild the cache. Two sources of non-determinism compounding. A lockfile would make re-runs deterministic: same lockfile, same code, every time. **No dependency tree visibility.** npm has `npm ls`. Cargo has `cargo tree`. You can inspect your full dependency graph, find duplicates, trace how a transitive dependency got pulled in. Actions gives you nothing. You can’t see what your workflow actually depends on without manually reading every composite action’s source. A lockfile would be a complete manifest of your dependency tree. **Undocumented resolution semantics.** Every package manager documents how dependency resolution works. npm has a spec. Cargo has a spec. Actions resolution is undocumented. The runner source is public, and the entire “resolution algorithm” is in ActionManager.cs. Here’s a simplified version of what it does: // Simplified from actions/runner ActionManager.cs async Task PrepareActionsAsync(steps) { // Start fresh every time - no caching DeleteDirectory("_work/_actions"); await PrepareActionsRecursiveAsync(steps, depth: 0); } async Task PrepareActionsRecursiveAsync(actions, depth) { if (depth > 10) throw new Exception("Composite action depth exceeded max depth 10"); foreach (var action in actions) { // Resolution happens on GitHub's server - opaque to us var downloadInfo = await GetDownloadInfoFromGitHub(action.Reference); // Download and extract - no integrity verification var tarball = await Download(downloadInfo.TarballUrl); Extract(tarball, $"_actions/{action.Owner}/{action.Repo}/{downloadInfo.Sha}"); // If composite, recurse into its dependencies var actionYml = Parse($"_actions/{action.Owner}/{action.Repo}/{downloadInfo.Sha}/action.yml"); if (actionYml.Type == "composite") { // These nested actions may use mutable tags - we have no control await PrepareActionsRecursiveAsync(actionYml.Steps, depth + 1); } } } That’s it. No version constraints, no deduplication (the same action referenced twice gets downloaded twice), no integrity checks. The tarball URL comes from GitHub’s API, and you trust them to return the right content for the SHA. A lockfile wouldn’t fix the missing spec, but it would at least give you a concrete record of what resolution produced. Even setting lockfiles aside, Actions has other issues that proper package managers solved long ago. **No registry.** Actions live in git repositories. There’s no central index, no security scanning, no malware detection, no typosquatting prevention. A real registry can flag malicious packages, store immutable copies independent of the source, and provide a single point for security response. The Marketplace exists but it’s a thin layer over repository search. Without a registry, there’s nowhere for immutable metadata to live. If an action’s source repository disappears or gets compromised, there’s no fallback. **Shared mutable environment.** Actions aren’t sandboxed from each other. Two actions calling `setup-node` with different versions mutate the same `$PATH`. The outcome depends on execution order, not any deterministic resolution. **No offline support.** Actions are pulled from GitHub on every run. There’s no offline installation mode, no vendoring mechanism, no way to run without network access. Other package managers let you vendor dependencies or set up private mirrors. With Actions, if GitHub is down, your CI is down. **The namespace is GitHub usernames.** Anyone who creates a GitHub account owns that namespace for actions. Account takeovers and typosquatting are possible. When a popular action maintainer’s account gets compromised, attackers can push malicious code and retag. A lockfile with integrity hashes wouldn’t prevent account takeovers, but it would detect when the code changes unexpectedly. The hash mismatch would fail the build instead of silently running attacker-controlled code. Another option would be something like Go’s checksum database, a transparent log of known-good hashes that catches when the same version suddenly has different contents. ### How Did We Get Here? The Actions runner is forked from Azure DevOps, designed for enterprises with controlled internal task libraries where you trust your pipeline tasks. GitHub bolted a public marketplace onto that foundation without rethinking the trust model. The addition of composite actions and reusable workflows created a dependency system, but the implementation ignored lessons from package management: lockfiles, integrity verification, transitive pinning, dependency visibility. This matters beyond CI/CD. Trusted publishing is being rolled out across package registries: PyPI, npm, RubyGems, and others now let you publish packages directly from GitHub Actions using OIDC tokens instead of long-lived secrets. OIDC removes one class of attacks (stolen credentials) but amplifies another: the supply chain security of these registries now depends entirely on GitHub Actions, a system that lacks the lockfile and integrity controls these registries themselves require. A compromise in your workflow’s action dependencies can lead to malicious packages on registries with better security practices than the system they’re trusting to publish. Other CI systems have done better. GitLab CI added an `integrity` keyword in version 17.9 that lets you specify a SHA256 hash for remote includes. If the hash doesn’t match, the pipeline fails. Their documentation explicitly warns that including remote configs “is similar to pulling a third-party dependency” and recommends pinning to full commit SHAs. GitLab recognized the problem and shipped integrity verification. GitHub closed the feature request. GitHub’s design choices don’t just affect GitHub users. Forgejo Actions maintains compatibility with GitHub Actions, which means projects migrating to Codeberg for ethical reasons inherit the same broken CI architecture. The Forgejo maintainers openly acknowledge the problems, with contributors calling GitHub Actions’ ecosystem “terribly designed and executed.” But they’re stuck maintaining compatibility with it. Codeberg mirrors common actions to reduce GitHub dependency, but the fundamental issues are baked into the model itself. GitHub’s design flaws are spreading to the alternatives. GitHub issue #2195 requested lockfile support. It was closed as “not planned” in 2022. Palo Alto’s “Unpinnable Actions” research documented how even SHA-pinned actions can have unpinnable transitive dependencies. Dependabot can update action versions, which helps. Some teams vendor actions into their own repos. zizmor is excellent at scanning workflows and finding security issues. But these are workarounds for a system that lacks the basics. The fix is a lockfile. Record resolved SHAs for every action reference, including transitives. Add integrity hashes. Make the dependency tree inspectable. GitHub closed the request three years ago and hasn’t revisited it. * * * **Further reading:** * Characterizing the Security of GitHub CI Workflows - Koishybayev et al., USENIX Security 2022 * ARGUS: A Framework for Staged Static Taint Analysis of GitHub Workflows and Actions - Muralee et al., USENIX Security 2023 * New GitHub Action supply chain attack: reviewdog/action-setup - Wiz Research, 2025 * Unpinnable Actions: How Malicious Code Can Sneak into Your GitHub Actions Workflows * GitHub Actions Worm: Compromising GitHub Repositories Through the Actions Dependency Tree * setup-python: Action can be compromised via mutable dependency
nesbitt.io
December 6, 2025 at 1:21 PM
David Beckham on Hot Ones:

"I love Lego"

I'm not into soccer, and enjoyed the look into what it's to work for 20 years traveling the world and appreciating local foods.

Also covers how the "Be honest" meme came to be.

https://www.youtube.com/watch?v=igmUnkx0fBw

#hotones #davidbeckham #behonest
December 7, 2025 at 11:40 PM
Reposted by Timo Tijhof
Thanks to @vsz this is quickly becoming the most thorough and detailed resource on the #openssl fork situation. Which fork does what and how?

https://github.com/curl/curl/wiki/OpenSSL-forks
OpenSSL forks
A command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP...
github.com
December 5, 2025 at 11:00 PM