The Applied Go Weekly Newsletter logo

The Applied Go Weekly Newsletter

Subscribe
Archives
July 13, 2025

Don't Mess With My Site! • The Applied Go Weekly Newsletter 2025-07-13

AppliedGoNewsletterHeader640.png

Your weekly source of Go news, tips, and projects

Don’t Mess With My Site!

Hi ,

There are myriad ways of attacking a web app, and cross-site request forgery is a particularly perfidious way of hijacking an authenticated web session. Luckily, modern browsers help fighting these attacks by sending information about a request’s origin, and Go 1.25 makes verifying this information a matter of a few lines of code.

Read the spotlight for more, but first learn about generic interfaces and interesting compilation targets.

Happy coding!

—Christoph

Featured articles

Generic interfaces - The Go Programming Language

Imagine you've built a generic tree type using cmp.Ordered, only to discover that you cannot use it with elements of type time.Time(), as they lack a comparison operator. Axel "The Merovius" Wagner found a way around this limitation.

Go Anywhere: Compiling Go for Your Router, NAS, Mainframe and Beyond! | by Jan Kammerath | Jul, 2025 | Medium

Go is known for effortless cross-compiling to a variety of operating systems and CPU architectures. Jan Kammerath takes this capability one step further and explores some rather unusual build targets.

Go 1.25 Release Candidate 2, Go 1.24.5, and Go 1.23.11 are released

Go 1.25, 1.24, and 1.23 have new minor point releases, fixing a security issue where specific uses of the Go toolchain in untrusted VCS repositories can result in unexpected code execution if multiple VCS configuration metadata is present. In trusted repositories, the previous behavior can be restored by setting GODEBUG=allowmultiplevcs=1.

Podcast corner

Fallthrough: What Even Is A [Programming|Natural] Language?

About humans talking to humans, humans talking to machines, and machines talking to machines.

Spotlight: Don't Mess With My Site!

Cross-Site Request Forgery (CSRF) is a tricky attack. Imagine you are logged in to your bank at yourbank.com to transfer some money. Something distracts you while the banking page is still open, and by bad luck, you get tricked into visiting evil.com. The page from evil.com contains a malicious script that sends a forged form to yourbank.com through a background POST request.

Because you have a banking session open in another tab, the forged from includes the session cookie. (Browsers don't limit cookies to a single tab, in order to allow users to open multiple tabs inside a session.)

Without a protection in place, the forged form could perform a money transfer from your bank account without you even noticing (until you check the transaction history).

(The above description might be an oversimplification, but the point is that without CSRF protection, malicious code loaded from domain A can intrude on an authenticated session of domain B.)

Modern browsers protect their users against CSRF by including headers in a request:

  • origin:<site> contains the site that the page that sent this request was loaded from
  • sec-fetch-site:same-origin if the request goes to the site listed in origin:
  • sec-fetch-site:cross-site if the request goes to a different site than the one listed in origin:

The web server that receives this request can check these headers to determine if the request is legit:

  • If the request is a GET, HEAD, or OPTIONS request, the request is valid. (These methods are always safe.)
  • If the origin is the site that receives the request, the request is valid.
  • If the origin is from a different site, sec-fetch-site says cross-site, and the origin isn't blacklisted on the web server, the request is valid.
  • In all other cases (origin header is missing, sec-fetch-site is missing), the request is rejected.

How can you make an http.Server detect CSRF attacks? With Go < 1.25, with carefully handcrafted code. With Go 1.25, the new type http.CrossOriginProtection has you covered.

Here is how it works (assuming you are the developer in charge of writing yourbank.com's money transfer handler):

You wrote a sophisticated handler like so:

transferHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    // This code must only run if CSRF protection passes!
    fmt.Fprintf(w, "Transfer successful!")
})

To add CSRF protection to the handler, create a new CrossOriginProtection value and add the origins your handler trusts. For example, if your users can load pages and data from yourbank.com and mobile.yourbank.com, add these as trusted origins. Then wrap your handler with the new cross-origin protection:

csrf := http.NewCrossOriginProtection()
csrf.AddTrustedOrigin("https://yourbank.com")
csrf.AddTrustedOrigin("https://mobile.yourbank.com")
protectedHandler := csrf.Handler(transferHandler)

Now wire the handler to the desired path (/transfer in this example) and start the server:

http.Handle("/transfer", protectedHandler)
fmt.Println("Server starting on :8080")
http.ListenAndServe(":8080", nil)

Done! Your handler is CSRF-protected.

Try it out: Paste the above Go code into a func main() add imports, and run it with Go 1.25 RC2 or later. (Find the full code, including package statement and imports, in the Go playground. It won't run there, but it's ready to copy&paste&run.)

Then test the following curl requests. (Note the --data "" flag that enforces a POST request.)

curl --data "" -H "sec-fetch-site:same-origin" http://localhost:8080/transfer
# "Transfer successful!"

curl --data "" -H "origin:https://yourbank.com" -H "sec-fetch-site:cross-site" http://localhost:8080/transfer
# "Transfer successful!"

curl --data "" -H "origin:https://evil.com" http://localhost:8080/transfer
# "cross-origin request detected, and/or browser is out of date: Sec-Fetch-Site is missing, and Origin does not match Host"

curl --data "" -H "sec-fetch-site:cross-site" http://localhost:8080/transfer
# "cross-origin request detected from Sec-Fetch-Site header"

curl --data "" -H "origin:https://evil.com" -H "sec-fetch-site:cross-site" http://localhost:8080/transfer
# "cross-origin request detected from Sec-Fetch-Site header"

Thwarting cross-site request forgery has become a good deal easier!

More articles, videos, talks

[Building a Golang Protoc Plugin to SQL Scan+Value Enums –

Badger Badger Badger Badger](https://badgerbadgerbadgerbadger.dev/posts/automation/2025-06-30-building-a-golang-protoc-plugin-to-sql-scan-value-enums/)

How to store protobuf enum values in databases as human-readable strings instead of their underlying integer representations.

What about an open-source #BigTech style development ecosystem for Go? | by Emiliano Arcamone | May, 2025 | Medium

Develop and deploy Go like the big boys but without the excessive complexity.

Developing a terminal UI in Go with Bubble Tea

If you haven't tried out Bubble Tea yet, Alex Pliutau's article is a great occasion for taking some first steps with this popular Terminal UI library.

Projects

Libraries

GitHub - unkn0wn-root/kioshun: Fast, sharded in-memory cache for Go with LRU/LFU eviction, TTL and object pooling.

In-memory caching with some useful features: automatic sharding, minimal lock contention, optimal shard count, memory efficiency, multiple eviction policies, hash function optimization, concurrent access, and more.

Tools and applications

GitHub - mochivi/distributed-file-system

An impressive solo project by a mechanical engineer who is transitioning over to software development.

GitHub - Oloruntobi1/pproftui: A terminal-based diagnostic tool for Go pprof data

The pprof tool has a useful web UI, but if you want to avoid the context switches to and from the web browser, pproftui is a terminal-based alternative for the web UI

GitHub - AndreRenaud/gore: Pure Go minimal Doom implementation

Doom, the legendary first-person shooter, has been ported to an array of unusual targets, including a robotic lawnmower and a thermostat.

Now it's ported to ... Go!

Completely unrelated to Go

A non-anthropomorphized view of LLMs

Humans tend to assign LLMs human-like capabilities like thinking, reasoning, or hallucinating. But Halvar Flake reminds us that an LLM "is just MatMul with interspersed nonlinearities" and continues to explain why anthropomorphization of LLMs is counterproductive to understanding LLMs.

Happy coding! ʕ◔ϖ◔ʔ

Questions or feedback? Drop me a line. I'd love to hear from you.

Best from Munich, Christoph

Not a subscriber yet?

If you read this newsletter issue online, or if someone forwarded the newsletter to you, subscribe for regular updates to get every new issue earlier than the online version, and more reliable than an occasional forwarding. 

Find the subscription form at the end of this page.

How I can help

If you're looking for more useful content around Go, here are some ways I can help you become a better Gopher (or a Gopher at all):

On AppliedGo.net, I blog about Go projects, algorithms and data structures in Go, and other fun stuff.

Or visit the AppliedGo.com blog and learn about language specifics, Go updates, and programming-related stuff. 

My AppliedGo YouTube channel hosts quick tip and crash course videos that help you get more productive and creative with Go.

Enroll in my Go course for developers that stands out for its intense use of animated graphics for explaining abstract concepts in an intuitive way. Numerous short and concise lectures allow you to schedule your learning flow as you like.

Check it out.


Christoph Berger IT Products and Services
Dachauer Straße 29
Bergkirchen
Germany

Don't miss what's next. Subscribe to The Applied Go Weekly Newsletter:
LinkedIn
Powered by Buttondown, the easiest way to start and grow your newsletter.