Skip to content

Security: cdrrazan/TweetX-web

Security

SECURITY.md

Security Policy

Supported Versions

TweetX-web is distributed as source, not as a released package. Security fixes land on main; there are no maintained release branches. Pull the latest main.

Reporting a Vulnerability

Please do not open a public issue for a security problem.

Report it privately through GitHub Security Advisories, or by email to irajanbhattarai@gmail.com.

Please include what you can: what the issue is, how to reproduce it, and what an attacker could achieve. You will get an acknowledgement within a few days. This is a personal project maintained in spare time, so please allow reasonable time for a fix before disclosing publicly.

Read this before you deploy it

TweetX-web was written as a single-user dashboard on localhost. It is honest about that, but the consequences are easy to miss, so they are spelled out here. None of the following is a vulnerability report — these are documented properties of the tool. If you deploy it to a public address without addressing them, the exposure is yours.

Authentication is a single hardcoded user. POST /login compares params[:username] and params[:password] against the TWEETX_USER and TWEETX_PASS environment variables with ==, in plaintext. There is no hashing, no rate limiting, no lockout, and no second factor. An attacker can guess passwords as fast as your server will answer.

The login form ships with demo credentials prefilled. views/login.erb prefills admin / password as a convenience for trying the app locally. Remove that before deploying anywhere reachable, and obviously do not use those values.

SESSION_SECRET signs the session cookie. Set it to a long random value — ruby -rsecurerandom -e 'puts SecureRandom.hex(64)'. Rack requires at least 64 characters. If it is empty, guessable, or shared across deployments, session cookies can be forged.

"Remember me" sets a 30-day cookie. It is httponly but not secure, so it will travel over plain HTTP if you serve the app over plain HTTP. Terminate TLS in front of it.

There is no CSRF protection. Every state-changing route is a plain form or fetch POST, and deletion happens over GET /delete/:id. A logged-in user visiting a hostile page can be made to delete or edit tweets.

The datastore is plain CSV, committed to git. Everything in data/ is public in a public repo, and every mutation rewrites the whole file with no locking. Concurrent writers can lose rows.

Credentials

The X API needs four OAuth 1.0a values (X_API_KEY, X_API_KEY_SECRET, X_ACCESS_TOKEN, X_ACCESS_TOKEN_SECRET), read from the environment via .env, which is gitignored. .env.sample is the template and contains no real values. If you fork this repo, check that you have not committed a real .env.

"Tweet Now" does not post

POST /tweet-now/:id is deliberately a simulation in this repo. It returns simulated: true, calls no API, and writes nothing. It previously reported success with a link to an unrelated real tweet, which was misleading; that is fixed, and there are specs holding it to it.

If you wire it up to post for real — the route comment names the exact change — then everything above about authentication and CSRF applies to an endpoint that publishes to a live account. Please think about that first.

There aren't any published security advisories