Bash can open a TCP socket and fake an HTTP request without curl

An engineer needed to ping a health endpoint between Docker containers. The image had no curl, no wget, no nc. So he opened /dev/tcp/service/8642 and typed the HTTP request by hand.

In brief

The trick is three lines: open file descriptor 3 on /dev/tcp, printf a raw GET with CRLF headers, then cat the descriptor back. The Connection: close header is load-bearing — drop it and cat waits forever.

But the loudest reply in the thread was a correction: Bash does not speak HTTP. It opens a socket and you speak HTTP, badly. The toy client doesn't parse responses and breaks on redirects, chunking, or TLS.

A container with no curl, no wget, no anything

The author hit a familiar wall: checking connectivity between containers on an internal Docker network where the image shipped with neither curl nor wget. His surprise was that Bash itself has /dev/tcp, a path that lets you open a raw socket and hand-write an HTTP request.

Bash /dev/tcp HTTP request
Bash /dev/tcp HTTP request

The three lines that do it

The recipe is small. Open a read-write file descriptor on the magic path, printf a raw request line plus CRLF headers, then read the descriptor back:

exec 3<>/dev/tcp/service/8642
printf 'GET /health HTTP/1.1\r\nHost: service\r\nConnection: close\r\n\r\n' >&3
cat <&3

The post is blunt about what this is not: "This is not a real HTTP client. It does not parse HTTP properly, handle redirects, chunked responses, compression, retries, TLS." The Connection: close header is mandatory, because without it the server holds the connection open and cat <&3 waits forever. It also needs Bash built with --enable-net-redirections, so dash and other POSIX shells are out.

Simon Willison tried it in the thread and hit the modern snag: HTTPS is everywhere.

Works against example.com … I always end up on example.com for this kind of thing because there are so few domains these days that don't enforce https! — Simon Willison, creator of Datasette

"No, it can not" — the framing pushback

The sharpest reply rejected the post's own headline claim that Bash speaks HTTP.

Bash lets you open TCP sockets. What you are doing here is trying to speak HTTP yourself … you will shoot yourself in the foot if you try to use this pseudo http client unattended in reality. — a commenter who links a full pure-Bash web server as proof of how far the hack goes

Then the thread veered somewhere the author didn't intend. Comment after comment described using /dev/tcp to escape locked-down boxes: an Envoy image with no curl, a 4MB router with no room for libcurl, a Powershell port that tripped CrowdStrike and got a developer mistaken for malware.

It's interesting that most of the comments here are about using this feature to bypass security restrictions … It says a lot about the attack surface of GNU utilities caused by featuritis. — Dmitry Chestnykh, founder of Coding Robots

The trick is also a post-compromise classic

One low-karma account named the dark side plainly: this is an old post-compromise move, used when an attacker has landed on a box and curl, wget, and nc are all missing. The same property that saves a sysadmin debugging a health check — a network client that's always present and needs nothing installed — is exactly what makes a stripped shell less safe than it looks. The cleaner read isn't "Bash speaks HTTP." It's that a socket primitive baked into every shell is a convenience and an attack surface at the same time.

Get breakdowns like this every day

The top Hacker News stories, unpacked — by email, Telegram, or RSS.

Next story · 20 of 23 Read more
🚀Tech

Tim Ferriss says his book catalog is down 57% on AI

The man who arguably built the modern self-help machine is now watching it drain. Ferriss's own backlist ran -5% in 2023, -13% in 2024, -46% in 2025, and a -57% run-rate in 2026.

★ 164 · 💬 173 · tim.blog · 3 min