DEV Community

Cover image for Edi Life OS v1.1: what a public security pass changed after launching on Hacker News
Edris
Edris

Posted on

Edi Life OS v1.1: what a public security pass changed after launching on Hacker News

Edi Life OS demo: tick a habit, ask Claude to log an expense, see it in Finance

A little while ago I posted Edi Life OS on Hacker News. It's a self-hosted dashboard for habits, goals, focus, money and projects, written in plain PHP, MySQL and vanilla JavaScript, with an MCP server so Claude and other assistants can work with your real data.

The launch brought a lot more eyes than I expected. More people looking at the code meant more people who would actually install it on their own servers, so the first release after launch had one theme: trust.

Here's what changed in v1.1, and what I learned doing it.

A security pass, written down in public

I went through the PHP backend and the frontend JavaScript and wrote every finding into one public issue, ordered by priority. Then I fixed them from the top.

High

  • Stored XSS on the dashboard. Goal titles, categories, metrics and finance category names were rendered with innerHTML without escaping. Those values can also be written through the bearer-token API, so API data could run script in the signed-in session. They're now escaped.
  • Open redirect after sign-in. The redirect parameter only had to start with / and not //, which browsers can be tricked around. It now has to be a real same-origin path.

Medium

  • CSRF on Habittify. Every write endpoint checked a CSRF token except the habit tracker's API. Now it does too, through one shared life_os_require_csrf() helper.
  • Sign-in rate limiting. After 5 failed attempts from one client in 15 minutes you get 429 with Retry-After, and the password isn't even checked. The limit is per IP (stored as a SHA-256 hash), not per username, so an attacker can't lock the owner out from everywhere.
  • Security headers. Content-Security-Policy, X-Frame-Options: SAMEORIGIN, Referrer-Policy and X-Content-Type-Options on every response. The CSP still allows inline scripts for now, because the app has inline handlers; moving them out is next.
  • HTTPS behind a reverse proxy. A new LIFEOS_TRUST_PROXY setting makes the session cookie Secure based on X-Forwarded-Proto and rate-limits by the real client IP. It's off by default, because trusting those headers on a directly exposed app would let anyone spoof them.

The lesson: with no framework, every protection a framework gives you for free (escaping, CSRF, headers) has to be built on purpose and applied everywhere. One endpoint that was written a little earlier than the others is enough to leave a gap.

A leaner MCP server

The MCP server never touches the database. Every tool goes through the same token-protected HTTP API the app uses, delete tools are marked destructive so the client asks first, and secret notes stay hidden unless the server explicitly allows them.

In v1.1, the 12 read-only tools became one lifeos_query tool with a type parameter (dashboard, goals, tasks, habits, finance_summary, notes and so on). Fewer tools means less of every conversation spent on tool descriptions, and an easier choice for the model.

Also new

  • Display currency. Finance started out Toman-only. You can now pick USD, EUR, GBP, AED and others in Settings. Amounts are labels and are never converted.
  • A landing page: edrisranjbar.github.io/lifeos
  • First outside contributions: CI that runs the PHP and Node tests on every PR, a Docker health check, and light-theme screenshots.

Try it

git clone https://github.com/edrisranjbar/lifeos.git && cd lifeos
cp .env.example .env   # change the username and passwords
docker compose up -d   # then open http://localhost:8080
Enter fullscreen mode Exit fullscreen mode

There's also a release zip for shared hosting: extract it, add your MySQL details, done.

If you self-host things: what's the first thing you check before you install an open-source app on your server? I'd love to hear it in the comments.

Top comments (1)

Collapse
 
suppdevbot profile image
DEV SUPPORTS •

You need to verify your account.

Enter fullscreen mode Exit fullscreen mode

tr.ee/dev-to