The Miner in ps Wasn’t Ollama, It Was a Container

A miner showed as user 'ollama' in ps, so I blamed the Ollama service for three days. It was a Postgres container whose UID collided with the host account.

For three days I was chasing the wrong process. A crypto-miner kept surfacing in ps, and every line of output pointed at the same owner: the ollama user. I had an Ollama service sitting on that box, so the story wrote itself. Local model server, unexplained CPU load, mining binary. Case closed.

It was not closed. The miner was running inside simstudio-db-1, a Postgres container, and the only thing connecting it to Ollama was a number.

What ps actually told me

The output looked decisive. A process with real CPU time, a real command line, and a user column reading ollama. On a normal single-namespace Linux box, that column is close to ground truth — the kernel tracks a UID per process, and the UID maps back to an account in /etc/passwd. When ps says a process runs as ollama, the usual inference is that the Ollama service started it, or that something compromised that account.

So I worked that inference. I treated Ollama as the patient: what it was doing, who could reach it, whether anything under its account had been touched. Three days of looking in the wrong place, because the premise was wrong, not the investigation.

The gotcha: UID is not identity

A UID is an integer. A username is a lookup. ps does that lookup for you and prints something human-readable, which is exactly what makes it lie so convincingly.

Inside the Postgres container, the process was running as some numeric UID — whatever the image assigned to its Postgres user. On the host, that same integer happens to belong to the ollama account. The container shares the host’s UID namespace, so the kernel sees one number and the userspace tools resolve it against the host’s account table. The result is a process that is unmistakably “ollama” in ps and has nothing whatsoever to do with Ollama.

Here is the part that stung: process ownership as reported by ps is meaningless as attribution when containers and host share a UID namespace. It tells you which integer owns the process. It does not tell you which service, which image, or which workload. Those are three different questions and only the first one was answered.

How the container gave itself away

The tell was never in the user column. It was in the shape of the process tree and in the fact that the miner’s parentage led back into container space rather than into anything Ollama had spawned. Once I stopped reading the owner and started reading the ancestry, simstudio-db-1 fell out immediately. A Postgres container running a crypto-miner is a stranger and more specific finding than “Ollama is compromised,” and it was sitting in the same output the whole time.

The decision that mattered was abandoning a hypothesis I had already spent three days on. The cheap move would have been to keep hardening Ollama — it feels like progress. The correct move was to ask what would have to be true for the owner column to be wrong, and then check that instead.

What I changed in how I read process lists

  • Treat the user column as a UID lookup, not an attribution. It is a name attached to an integer by the host’s account table.
  • When a process looks out of place, read the ancestry before the owner. The parent chain survives namespace confusion far better than a resolved username.
  • On any host running containers, assume UID collisions exist until proven otherwise. Multiple images pick low, common numeric UIDs, and the host has accounts at those same numbers.
  • Keep a container-to-UID mapping in mind when triaging. “Which container could produce this integer” is a faster question than “which service is misbehaving.”

The outcome

The miner was inside simstudio-db-1, not inside Ollama. Three days of my attention went to an innocent service because I trusted a resolved username over the actual process tree. The fix on my side was procedural, not technical: I stopped treating ps ownership as evidence of who launched something, and started treating it as one weak signal among several. The miner is a separate problem. The misattribution was mine, and it cost three days.

Related

Filed under: Cybersecurity, Docker, PostgreSQL, Security Hardening, VPS