🔒 How We Secured MyZubster – and How You Can Help Improve It Further
Building a full‑stack application is one thing. Building a secure one is another. When I launched MyZubster, I knew that security couldn't be an afterthought – it had to be baked into every layer.
In this article, I'll walk you through the security issues we identified, the fixes we implemented, and the areas where we still need your help.
🧠 The Security Mindset
Before diving into the code, let's talk about the philosophy:
- Defense in depth – multiple layers of protection.
- Principle of least privilege – containers run as non‑root.
- Keep dependencies updated – no known vulnerabilities.
- Community review – many eyes make bugs shallow.
With these principles in mind, we audited the entire MyZubster stack.
🐛 Issues We Found and Fixed
1. CVE-2023-45857 – Axios Vulnerable
Problem: MyZubster used axios@1.18.1, which is vulnerable to CSRF attacks (CVE-2023-45857).
Impact: An attacker could craft malicious requests and perform unauthorized actions.
Fix:
bash
npm install axios@1.7.9
We upgraded to the latest secure version in both the frontend and the gateway.
Takeaway: Always monitor CVE databases for your dependencies. Tools like npm audit and cargo audit are your friends.
2. Missing CSRF Protection
Problem: State‑changing endpoints (POST, PUT, DELETE) had no CSRF tokens.
Impact: Users could be tricked into executing unwanted actions.
Fix:
We implemented a token‑based CSRF middleware in the gateway:
javascript
const csrf = require('csrf');
const tokens = new csrf();
app.use((req, res, next) => {
const secret = tokens.secretSync();
const token = tokens.create(secret);
res.cookie('XSRF-TOKEN', token, { httpOnly: true, sameSite: 'strict' });
req.csrfToken = token;
next();
});
app.use((req, res, next) => {
if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(req.method)) {
const token = req.headers['x-xsrf-token'] || req.body._csrf;
if (!tokens.verify(req.csrfToken, token)) {
return res.status(403).json({ error: 'Invalid CSRF token' });
}
}
next();
});
Takeaway: Every state‑changing endpoint needs protection. Don't rely only on CORS.
3. Docker Running as Root
Problem: The Docker container was running with root privileges.
Impact: If an attacker exploited the container, they'd have root access to the host system.
Fix:
We created a non‑root user inside the Dockerfile:
dockerfile
RUN groupadd -r myzubster && useradd -r -g myzubster myzubster
USER myzubster
All processes now run with limited permissions.
Takeaway: Never run containers as root. Use USER in Dockerfile and --user in docker run.
4. Missing CORS Configuration
Problem: The Rust backend didn't allow cross‑origin requests.
Impact: The React frontend couldn't communicate with the API.
Fix:
We added the tower-http CORS layer:
rust
use tower_http::cors::{Any, CorsLayer};
let cors = CorsLayer::new()
.allow_origin(Any)
.allow_methods(Any)
.allow_headers(Any);
let app = Router::new()
.route("/health", get(health_check))
.route("/orders", get(get_orders))
.layer(cors);
Takeaway: For development, allow Any; for production, restrict to your domain.
5. Missing HTTPS
Problem: All traffic was in plain HTTP.
Impact: Man‑in‑the‑middle attacks could read and modify data.
Fix:
We configured Nginx as a reverse proxy with Let's Encrypt SSL certificates (planned for production).
nginx
server {
listen 443 ssl;
server_name your-domain.com;
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
# ...
}
Takeaway: HTTPS is non‑negotiable. Use Let's Encrypt for free, automated certificates.
6. Outdated Dependencies
Problem: Several dependencies were outdated, not just Axios.
Impact: Hidden vulnerabilities.
Fix:
We ran npm audit and cargo audit, updated all packages, and removed unused ones.
bash
npm audit fix --force
cargo update
Takeaway: Regularly audit your dependencies. It's a small effort for a huge gain.
🛡️ Security Checklist (Status)
Security Feature Status
CORS ✅ Done
CSRF ✅ Done
Docker Non‑Root ✅ Done
Axios Update ✅ Done
Dependency Audit ✅ Done
HTTPS 📝 Planned (Let's Encrypt)
Rate Limiting 📝 Planned
Input Validation 📝 Planned
SQL Injection Prevention ✅ Done (using parameterized queries)
Secrets Management ✅ Done (using .env files)
🤝 How You Can Help
Security is a continuous process, not a one‑time fix. We're inviting you – the community – to help us make MyZubster even more secure.
Ways to Contribute
Task Difficulty Impact
Code Review 🟢 Easy High
Security Audit 🟡 Medium Very High
Bug Bounty 🔴 Hard Very High
Improve Documentation 🟢 Easy Medium
Add Tests 🟡 Medium High
Implement HTTPS 🟡 Medium High
Add Rate Limiting 🟡 Medium High
How to Get Started
Explore the code – GitHub (public)
Open an issue – report anything suspicious.
Submit a PR – fix a security issue or add a feature.
Join the discussion – share your ideas.
What We're Looking For
Penetration testing – try to break it (ethically).
Dependency scanning – check for known vulnerabilities.
Best practices – suggest improvements.
Documentation – help others deploy securely.
📦 How to Run MyZubster Locally
bash
# Clone the repo
git clone https://github.com/DanielIoni-creator/MyZubster.git
cd MyZubster
# Start the Rust backend
cd my_first_nft/nft
cargo run
# Start the React frontend (in another terminal)
cd myzubster-frontend
npm install
npm run dev
# Access the dashboard
open http://localhost:5173
📬 Connect with Me
If you're interested in security, Rust, or Web3, let's connect!
📖 Dev.to: https://dev.to/danielioni
🐦 X (Twitter): https://x.com/myzubster
💼 LinkedIn: https://linkedin.com/in/daniel-ioni-62b2b9423/
🐙 GitHub: https://github.com/DanielIoni-creator
🔗 Links
GitHub (NFT template): https://github.com/DanielIoni-creator/tari-nft-template
Docker Hub: https://hub.docker.com/repository/docker/myzubster/tari-nft-template
MyZubster (private): https://github.com/DanielIoni-creator/MyZubster
Built with ❤️ and 🔒 for the Monero and Tari community.
🚀 Together, we can make MyZubster a benchmark for secure Web3 applications. Join us! 🔒
text__
Top comments (0)