<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Go Security in Production on Atharva Pandey</title><link>https://atharva.page/series/go-security-in-production/</link><description>Recent content in Go Security in Production on Atharva Pandey</description><generator>Hugo</generator><language>en-us</language><copyright>Copyright ©</copyright><lastBuildDate>Mon, 05 May 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://atharva.page/series/go-security-in-production/index.xml" rel="self" type="application/rss+xml"/><item><title>Lesson 9: Dependency Scanning — govulncheck before you deploy</title><link>https://atharva.page/post/go/go-sec-dependency-scanning/</link><pubDate>Mon, 05 May 2025 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-sec-dependency-scanning/</guid><description>&lt;p&gt;The security posture of your Go application is not just about the code you write — it is also about the code you import. A typical Go microservice will have dozens of direct and transitive dependencies. Any one of them might have a known vulnerability in the specific version you are using. Unlike the bugs in your own code, these vulnerabilities are publicly catalogued, exploits are often published, and attackers scan for them at scale.&lt;/p&gt;</description></item><item><title>Lesson 8: Secure HTTP Defaults — Your production server needs these headers</title><link>https://atharva.page/post/go/go-sec-http-defaults/</link><pubDate>Mon, 10 Mar 2025 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-sec-http-defaults/</guid><description>&lt;p&gt;When I run the Go HTTP server in the standard library with no configuration, it does a lot of things right — it is fast, it handles HTTP/2, it is well-tested. But it also does a handful of things that are wrong for production: no timeouts, no response headers that protect against common browser-based attacks, and server identification information in responses. These are not bugs in the standard library; they are defaults appropriate for development that need to be changed before you deploy.&lt;/p&gt;</description></item><item><title>Lesson 7: JWT Caveats — JWTs are not sessions</title><link>https://atharva.page/post/go/go-sec-jwt/</link><pubDate>Sat, 18 Jan 2025 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-sec-jwt/</guid><description>&lt;p&gt;JWT has become the default answer to &amp;ldquo;how should I handle authentication tokens?&amp;rdquo; in the Go community. I have shipped JWTs in production and I have also shipped systems that would have been much simpler and more secure with server-side sessions. The point of this lesson is not that JWTs are bad — it is that they carry specific security risks that are easy to overlook, and they solve a specific problem (stateless authentication across services) that not every application actually has.&lt;/p&gt;</description></item><item><title>Lesson 6: Password Hashing — bcrypt or argon2, nothing else</title><link>https://atharva.page/post/go/go-sec-password-hashing/</link><pubDate>Mon, 02 Dec 2024 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-sec-password-hashing/</guid><description>&lt;p&gt;Password hashing is one of those topics where the correct answer is short and clear, the wrong answers are numerous and subtle, and developers who confidently implement one of the wrong answers often do not know they did anything wrong until a database is leaked and journalists start writing about it. I have sat in a post-mortem where the words &amp;ldquo;we were using MD5&amp;rdquo; were spoken in a conference room full of very quiet people. That was not my code, but I understood how it happened — MD5 was the &amp;ldquo;hash function&amp;rdquo; the developer knew, and they did not realize it was entirely unsuitable for passwords.&lt;/p&gt;</description></item><item><title>Lesson 5: Auth Middleware — Authentication is not authorization</title><link>https://atharva.page/post/go/go-sec-auth-middleware/</link><pubDate>Tue, 22 Oct 2024 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-sec-auth-middleware/</guid><description>&lt;p&gt;A few years ago I audited a Go API where every endpoint was protected by an authentication middleware. The middleware checked for a valid JWT, extracted the user ID, and set it in the request context. The developer was proud of it — every route was secured. The problem was that the product had a concept of &amp;ldquo;organizations&amp;rdquo; — users belonged to organizations — and the API let you fetch any organization&amp;rsquo;s data as long as you were authenticated. The authentication was solid. The authorization was completely absent.&lt;/p&gt;</description></item><item><title>Lesson 4: SSRF and Injection — The URL your user gave you might be localhost</title><link>https://atharva.page/post/go/go-sec-ssrf-injection/</link><pubDate>Wed, 18 Sep 2024 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-sec-ssrf-injection/</guid><description>&lt;p&gt;I reviewed a Go service that let users provide a &amp;ldquo;webhook URL&amp;rdquo; — we would call that URL when their account had a notification. The service fetched a preview of the URL to display in the UI. The developer who built it figured that since it only fetched the URL and never executed what was returned, it was safe. They had not considered that &lt;code&gt;http://169.254.169.254/latest/meta-data/iam/security-credentials/&lt;/code&gt; is also a URL.&lt;/p&gt;
&lt;p&gt;SSRF — Server-Side Request Forgery — is the class of vulnerability where an attacker tricks your server into making an HTTP request to a target of their choosing, typically to access internal services that are not exposed to the internet. AWS instance metadata, Redis, internal Kubernetes API servers, admin dashboards, other services in your VPC — all are reachable from a server that blindly follows user-supplied URLs.&lt;/p&gt;</description></item><item><title>Lesson 3: TLS Configuration — Your default HTTP server is unencrypted</title><link>https://atharva.page/post/go/go-sec-tls/</link><pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-sec-tls/</guid><description>&lt;p&gt;When I started writing Go HTTP servers, I thought TLS was someone else&amp;rsquo;s problem. A load balancer in front of my service handled HTTPS termination, so my service only ever spoke plain HTTP on the internal network. That is a common and often defensible architecture. But it means that if anyone gains access to your internal network — a compromised service, a misconfigured cloud security group, a rogue container — all traffic between your services is plaintext. I learned this lesson not from a breach but from a penetration test report that listed it as a finding with a crisp paragraph explaining exactly why it mattered.&lt;/p&gt;</description></item><item><title>Lesson 2: Secret Handling — Env vars are not a vault</title><link>https://atharva.page/post/go/go-sec-secrets/</link><pubDate>Mon, 08 Jul 2024 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-sec-secrets/</guid><description>&lt;p&gt;I once found database credentials committed directly in a Go source file — not in a toy project, in a staging environment of a real product. The developer who wrote it knew it was wrong, but they were &amp;ldquo;just testing&amp;rdquo; and forgot to revert it. That file lived in the repository for eight months before anyone noticed. By then, the credentials had been rotated, but the history was permanent.&lt;/p&gt;
&lt;p&gt;Secret handling in Go is not primarily a coding problem. It is a discipline problem. The code patterns are simple. The failures happen when you treat secrets as a detail to clean up later, or when you assume that environment variables are inherently safe because they are not in source code.&lt;/p&gt;</description></item><item><title>Lesson 1: Input Validation — Trust nothing from the wire</title><link>https://atharva.page/post/go/go-sec-input-validation/</link><pubDate>Wed, 05 Jun 2024 00:00:00 +0000</pubDate><guid>https://atharva.page/post/go/go-sec-input-validation/</guid><description>&lt;p&gt;The first production security incident I dealt with involved a simple integer field in a JSON body. The client sent a negative number where we expected a positive quantity. We hadn&amp;rsquo;t validated it. The result was a negative charge on a purchase — we were effectively paying customers money. That taught me more about input validation than any security course.&lt;/p&gt;
&lt;p&gt;Every byte that arrives over the wire is adversarial by default. Not because every user is malicious, but because your assumptions about the data are not enforced by anything except your own code. HTTP gives you a byte stream. JSON decoding gives you Go values. Neither of those steps checks whether the values make sense for your business logic. That job is yours.&lt;/p&gt;</description></item></channel></rss>