Self-hosted service
snoopysecurity/dvws-node avatar
snoopysecurity/dvws-node

dvws-node is a deliberately breakable Node API to practise on

Damn Vulnerable Web Services is a vulnerable application with a web service and an API that can be used to learn about webservices/API related vulnerabilities.

521 stars246 forksJavaScriptGPL-3.0

At a glance

What is it?
dvws-node is an intentionally vulnerable Express and GraphQL service that bundles more than thirty web and API flaws into one Node application, plus the Docker databases and seed script needed to run it. It is a training target that must never face a real network, and its licence metadata contradicts itself.
Who is it for?
Use dvws-node when you want a single local target that demonstrates IDOR, mass assignment, injection classes and GraphQL access control without building your own lab. Do not deploy it anywhere reachable, since the point of the project is that the flaws are present on purpose, and the published solutions make each one trivial to find.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 46 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A service built to be broken on purpose

dvws-node is a vulnerable application with a web service and an API, and the project states plainly that it is meant to be used to learn about web service and API related vulnerabilities. It replaces an earlier Python project of the same name, and it is packaged as a Node application with a Svelte frontend, an Express API, a GraphQL endpoint, Swagger documentation and two databases.

The audience is developers learning application security, instructors who need a lab target, and engineers who want a reproducible environment in which every flaw is already planted rather than hunted. The repository carries a Security badge labelled Intentionally Vulnerable and a Gitpod Ready-to-Code badge, which tells you the intended way to use it: open it in a disposable environment, read the challenge list, exploit the endpoint, then check the write up.

That framing matters for how you read the rest of the project. Every dependency choice that would look reckless in a production service is here to create a teaching moment. The Express stack has no CSRF protection, the GraphQL server exposes introspection and allows arbitrary file writes, and the token secret is weak enough to brute force. The application is a lab, and the interesting question is never whether it is safe but which lesson each route teaches.

The catalogue covers thirty flaws, and the to do list names the gaps

The vulnerability list is the specification of the project. It covers Insecure Direct Object Reference, horizontal and vertical access control issues, mass assignment, Cross-Site Scripting, NoSQL Injection, Server Side Request Forgery, JSON Web Token secret key brute force, information disclosure, hidden API functionality exposure, Cross-Origin Resource Sharing misconfiguration, JSON hijacking, SQL Injection, XML External Entity Injection, command injection, XPATH injection, XML-RPC user enumeration, open redirect, path traversal, unsafe deserialization, sensitive data exposure, GraphQL access control issues, GraphQL introspection enabled, GraphQL arbitrary file write, GraphQL batching brute force, API endpoint brute forcing, CRLF injection, XML injection, XML bomb denial of service, SOAP injection, CSRF, rate limit bypass and client side template injection.

The To Do section is as informative as the list itself. Web Socket security, type confusion, LDAP injection, GraphQL denial of service, GraphQL injection, webhook security, parameter pollution and OAuth2 and OIDC flow flaws are named as work still to come, so the catalogue is understood by its author as incomplete.

Solutions are published as a challenge document in the repository and through the project wiki, which is what turns the application into a course rather than a curiosity.

The stack shows the shape of each lesson

Looking at the dependency list tells you how the flaws are made. Express and body-parser handle HTTP input, cors is present without restriction, express-jwt-permissions provides the authorization layer whose horizontal and vertical access control bugs are the point, and swagger-autogen with swagger-ui-express generate the API documentation, including the hidden functionality the project says is exposed.

Two database clients sit side by side so that SQL and NoSQL injection can both be demonstrated: mongoose for MongoDB and mysql2 with sequelize for MySQL. The NoSQL side is where node-serialize appears, giving the unsafe deserialization lesson, and needle provides the HTTP client for the server side request forgery route. For XML there is xml2js, xpath and libxmljs2, which is also the native module that makes the install step awkward. xmlrpc covers the XML-RPC user enumeration challenge, pdfkit and express-fileupload cover file handling, and graphql with apollo-server and apollo-server-express powers the GraphQL endpoints. jsonwebtoken signs the tokens and bcrypt hashes passwords.

A frontend directory sits beside src, and the Dockerfile shows a Svelte build step that emits into the public directory, so the served interface and the API come from one image.

Bringing the stack up with Docker Compose

The compose route is the shortest path to a running target. The repository ships a docker-compose.yml with three services: dvws-mongo running mongo:4.0.4, dvws-mysql running mysql:8, and a web service built from the Dockerfile. Both databases declare health checks, and the web service waits for them to report healthy before it starts.

bash
git clone https://github.com/snoopysecurity/dvws-node.git
cd dvws-node
docker-compose up

The compose file publishes the application on port 80 and passes two connection strings into the container environment, SQL_LOCAL_CONN_URL pointing at the dvws-mysql host and MONGO_LOCAL_CONN_URL pointing at the MongoDB service and its node-dvws database. The start command runs the seed script and then the server in one shell line, so the test data is created before the API answers.

If the web service comes up before its databases are ready, the documentation tells you to raise the value of the environment variable WAIT_HOSTS_TIMEOUT. The compose file also declares a start_period of 10s for the database health checks, which is the window during which a container can still be warming up.

Running it by hand, including the native build that bites people

The manual route needs Node and npm, and the instructions list what was tested: node v20.x or v22.x with npm 10.x. The two databases are started as containers, MongoDB on port 27017 and MySQL on port 3306, with the MySQL container given a root password and a database named dvws_sqldb.

bash
docker run -d -p 27017-27019:27017-27019 --name dvws-mongo mongo:4.0.4
docker run -p 3306:3306 --name dvws-mysql -e MYSQL_ROOT_PASSWORD=mysecretpassword -e MYSQL_DATABASE=dvws_sqldb -d mysql:8

The repository is then cloned and installed. The install step is where people lose time, because libxmljs2 has to be compiled from source and the documentation notes you may also need libxml installed depending on your operating system.

bash
git clone https://github.com/snoopysecurity/dvws-node.git
cd dvws-node
npm install --build-from-source

Test data is created by a seed script, and the application is started with npm start. The documentation notes that sudo privileges are needed to bind to port 80, which is the default, and that you can change the port in the .env file to avoid needing sudo.

bash
node scripts/seed-database.js
sudo npm start

One optional finishing touch matters if you follow the Swagger links: add a hosts entry so that localhost resolves to dvws.local, which keeps the generated documentation URLs correct.

bash
127.0.0.1    dvws.local

The mocha suite turns the flaws into repeatable checks

The package.json defines five scripts, and two of them make the project usable as a course. The test script runs mocha, test:vulnerabilities runs mocha against test/vulnerabilities.test.js with a 10000 millisecond timeout, and test:all runs mocha across every test file in the test directory with the same timeout. The seed and start scripts wrap node scripts/seed-database.js and node src/server.js.

The dev dependencies give the shape of that suite: mocha as the runner, supertest for driving the HTTP endpoints from inside the test process, and chai for assertions. That combination means the vulnerabilities can be exercised as automated checks rather than clicked through manually, which is what lets a learner confirm an exploit instead of guessing.

A CHALLENGES.md file sits at the top level next to the source, and the documentation links it as the solutions reference with the project wiki as an alternative. The repository also carries a fixtures directory and a test directory alongside src and public, so the seeded data and the assertions live close to the code they exercise.

Licence metadata disagrees, and the release history is empty

The licence situation needs a careful read. The repository is recorded under GPL-3.0, while the package.json declares the field "license": "MIT". Those two statements do not agree, and for a project people fork and repackage for training, which one governs is a question for the copyright holder rather than something to guess at. Read the LICENSE file in the repository before you redistribute a modified version.

On maintenance, the facts are thin. The repository publishes no GitHub releases, and the last push was on 2026-09-07, which is recent enough that the code moves, yet there is no version history to consult. The package version in package.json is 0.0.1, so nothing in the manifest communicates the state of the tree.

Runtime expectations are stated, though, and they are a real upgrade cost: node v20.x or v22.x with npm 10.x, and a source build for libxmljs2 that needs a compiler toolchain on your machine. The Dockerfile handles that for you by installing python3, make, g++ and build-essential on a node:22 base image, so the container route avoids the native build problem entirely.

Editorial conclusion

Use dvws-node when you want a single local target that demonstrates IDOR, mass assignment, injection classes and GraphQL access control without building your own lab. Do not deploy it anywhere reachable, since the point of the project is that the flaws are present on purpose, and the published solutions make each one trivial to find. Before you start, verify the container listens only on your loopback interface, decide whether the MIT field in package.json or the GPL-3.0 repository licence applies to your use of the code, and check that the Node version you run matches the v20.x and v22.x lines the setup instructions were tested on, since the last push was on 2026-09-07.

Frequently asked questions

How do I start dvws-node with Docker Compose?

Clone the repository, change into the dvws-node directory and run docker-compose up. The compose file starts a MongoDB service, a MySQL service and the web service, which seeds the database and then starts the API on port 80.

What do I do if the dvws-node web service fails to start because MongoDB or MySQL is not ready?

Increase the value of the environment variable WAIT_HOSTS_TIMEOUT. The compose file also gives each database a health check with a start period of 10 seconds before the web service depends on it.

Which vulnerability classes does dvws-node still need to add?

The To Do list names Web Socket security, type confusion, LDAP injection, GraphQL denial of service, GraphQL injection, webhook security, parameter pollution and OAuth2 and OIDC flow flaws.

Do I need root privileges to run dvws-node locally?

Only if you keep the default port 80, since binding to it needs sudo. The documentation says you can change the port in the .env file to avoid it.

Can the dvws-node vulnerabilities be checked automatically?

Yes. The package.json defines mocha scripts including test:vulnerabilities, which runs mocha against test/vulnerabilities.test.js with a 10000 millisecond timeout, and test:all which runs every test file. The dev dependencies are mocha, supertest and chai.

Official sources

  1. Issues
  2. License: GPL-3.0
  3. README
  4. snoopysecurity/dvws-node on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/snoopysecurity-dvws-node.svg)](https://hysenlabs.com/projects/snoopysecurity-dvws-node)

Was this useful?