# Project export: Turwin

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2025
- Tagline: APIs power digital infrastructure, but flaws like IDORs expose sensitive data in fields like healthcare. Our AI-driven security platform detects vulnerabilities proactively for scalable protection.
- Devpost: https://devpost.com/software/turwin
- GitHub: https://github.com/Turwin1729/turwin.git
- Video: https://www.youtube.com/embed/ufybKfLj0Lk?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — Taha Biyikli (14 commits), Su Kara (2 commits), Berwyn19 (1 commits)

## Devpost submission (written by the team)

### Inspiration

API security testing is stuck between two broken approaches. Automated scanners quickly find basic vulnerabilities but miss critical logic flaws, while human security researchers can catch these flaws through intuition and understanding but take weeks. Companies need continuous testing but can’t scale human analysis or rely on basic automation. We built the Turwin to solve this problem. Turwin is an agentic workflow that integrates novel LLM-based and conventional solutions to finding critical vulnerabilities in web and mobile APIs. This enables our hackbot to operate just like a skilled security researcher on applications. Through the electronic healthcare system (EHR) simulations we have made, we show that Turwin can scan for and find vulnerabilities in seconds, eliminating the need for the painstaking manual analysis that security researchers typically go through.

### What it does

Turwin is a hackbot that can detect unauthorized access vulnerabilities on an API. In particular, it focuses on access control vulnerabilities that currently no open source cybersecurity automation can detect. Below is an example that showcases Turwin's capabilities. In our case, we use an EHR simulation, where users can register as either patients or doctors. Patients can update their profile details and view their own test results, while doctors can create and access test results for specific patients. To make Turwin modular and easy to maintain, we have made our EHR simulation plain and simple, implementing only fundamental features of modern EHRs. Let’s say Alice, a patient, logs in and requests her test results through an API call like: GET /api/test_results?patient_id=123 But what happens if Alice manually changes the patient ID to Bob’s (456) in the request? GET /api/test_results?patient_id=456 If the API doesn’t properly enforce access control policies in their codebase, this endpoint could return Bob’s private medical records to Alice upon request, which would have caused a serious security breach. Turwin detects this vulnerability long before it can be exploited by malicious parties. Preferably, Turwin would be run in development and staging environments by companies, long before products meet the end users.

### How we built it

Turwin uses two important files to make an initial LLM call: The website’s OpenAPI specification File composed of request-response pairs from a scan of the website. The OpenAI spec is crucial because it defines the request syntax and intended behavior of different calls to the endpoint, allowing us to restrict our search of vulnerabilities to valid requests that fit the format that the API expects. For the request-response pair file, we use a custom crawler built through Playwright which takes advantage of the fact that the ui is the intended behavior for the apis. Turwin uses an LLM-powered analyzer which can find the “objects” in a website. We define “objects” as elements which allow for the interaction and manipulation of webpages. Our crawler feeds the “objects” and two files above into an LLM, which creates what we call an initial permission model. This permission model is updated as new requests reveal updates to objects in the web application and show objects that have not been seen before. To test Turwin, we developed a custom vulnerable application, Turwin Medical Center, which simulates a patient-doctor portal. This application is containerized using Docker to allow for easy deployment and controlled testing environments. To provide a user-friendly interface, we built the Turwin application using Windsurf, which enables users to input an OpenAPI specification file and visualize the API structure in a tree format. This interactive visualization allows users to hover over different nodes to scan for vulnerabilities.

### Challenges we ran into

One of the biggest challenges was defining what an “object” is to an LLM. While humans can easily determine interactive elements from request-response pairs (e.g., user, patient, doctor), conveying this understanding to an LLM is complex. Parsing the OpenAPI spec and network logs in a way that allows the LLM to extract meaningful access control rules required extensive experimentation. Building the crawler also presented significant difficulties. We needed a mechanism that could not only navigate complex frontends but also capture interactions that reveal the true behavior of the underlying APIs. Handling dynamic content and authentication mechanisms while ensuring accurate request-response pair extraction was a major hurdle. Additionally, designing an effective permission model that adapts as new interactions are discovered was non-trivial. Ensuring that Turwin could update its model dynamically without requiring excessive retraining was crucial to making it scalable.

### Accomplishments we're proud of

We successfully created a modular framework that can be expanded to automatically detect security vulnerabilities in websites. Unlike existing solutions that rely on either static analysis or human-driven penetration testing, Turwin bridges the gap by combining automation with intelligent reasoning, reducing the time needed to identify access control flaws significantly. Another major accomplishment was building a realistic and controlled testing environment using our custom EHR simulation. This allowed us to validate Turwin’s capabilities against real-world use cases in a way that is both reproducible and extensible. Finally, we’re proud of the usability of Turwin. By integrating an intuitive visualization interface with automated security analysis, we’ve made it easier for security teams to test APIs without requiring extensive manual effort.

### What we learned

We gained a deeper understanding of the complexities of API security testing, particularly around access control vulnerabilities, which remain one of the hardest categories to automate. The process also reinforced the importance of balancing LLM-based automation with traditional cybersecurity techniques to achieve meaningful results. We also learned a lot about the limitations and strengths of using LLMs for security analysis. While they can infer logical structures and patterns efficiently, ensuring accuracy requires high-quality input data and clear contextual guidance. Additionally, our experience with building a crawler that accurately extracts real-world interactions showed us the importance of grounding automation in realistic use cases rather than synthetic or theoretical data.

### What's next

Moving forward, we want to refine the object identification process further. Instead of treating objects statically, we aim to implement a more dynamic approach where objects and their associated permissions are continuously refined based on new interactions observed in live applications. We also plan to expand Turwin’s capabilities beyond detecting unauthorized access vulnerabilities. Future iterations will include detection of business logic flaws, race conditions, and API misconfigurations that are often overlooked by conventional scanners. Additionally, we want to improve integration with existing security tools and CI/CD pipelines, allowing organizations to seamlessly incorporate Turwin into their development workflows. This will help ensure that security testing happens continuously and at scale. Ultimately, our goal is to make Turwin the go-to security assistant for API testing, combining the speed of automation with the depth of human-like analysis.

## README (from the GitHub repository)

# Treehacks 2025 Turwin Project
Taha Biyikli, Su Kara, Berwyn Berwyn

Link to devpost with more information: https://devpost.com/software/turwin


## Detected evidence (automated analysis)

Indexed codebase: 51 recognized source files, 181 KB.
- CSS (language) — detected in the code
- Flask (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- OpenAI (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code

## Codebase structure (from repository index)

### Files (97 of 97)

```
.gitignore
fuzzer/__init__.py
fuzzer/fuzzer_test.py
fuzzer/fuzzer.py
lab/app.py
lab/db_states/clean_install/hospital.db_2025-02-15_14-45-27
lab/db_states/clean_install/metadata.json
lab/db_states/test_users/hospital.db_2025-02-15_14-46-25
lab/db_states/test_users/metadata.json
lab/docker-compose.yml
lab/Dockerfile
lab/frontend/.gitignore
lab/frontend/Dockerfile
lab/frontend/nginx.conf
lab/frontend/package.json
lab/frontend/public/index.html
lab/frontend/public/manifest.json
lab/frontend/public/robots.txt
lab/frontend/README.md
lab/frontend/src/App.css
lab/frontend/src/App.js
lab/frontend/src/App.test.js
lab/frontend/src/assets/hospital.jpg.bak
lab/frontend/src/components/DoctorDashboard.js
lab/frontend/src/components/Login.js
lab/frontend/src/components/Navbar.js
lab/frontend/src/components/PatientDashboard.js
lab/frontend/src/components/Register.js
lab/frontend/src/index.css
lab/frontend/src/index.js
lab/frontend/src/reportWebVitals.js
lab/frontend/src/setupTests.js
lab/hospital.db
lab/hospital.db.backup
lab/manage_state.sh
lab/nginx.conf
lab/openapi.json
lab/README.md
lab/requirements.txt
lab/static/custom.css
lab/templates/base.html
lab/templates/doctor_dashboard.html
lab/templates/index.html
lab/templates/login.html
lab/templates/patient_dashboard.html
lab/templates/register.html
llm/create_mask.py
llm/find_operations.py
llm/network_log_20250216_020554.json
llm/parse_two_users_xml.py
llm/parse_xml.py
oracle/.gitignore
oracle/backup/oracle.py
oracle/backup/requirements.txt
oracle/backup/test_oracle.py
oracle/network_log.json
oracle/objects.json
oracle/openapi.json
oracle/oracle.py
oracle/permission_model.csv
oracle/permission_model.py
oracle/README.md
oracle/requirements.txt
oracle/test_oracle.py
oracle/test_permission_model.py
play/credentials.csv
play/network_log_20250216_015457.json
play/network_log_20250216_015657.json
play/network_log_20250216_015953.json
play/network_log_20250216_020554.json
play/network_log_20250216_021329.json
play/network_log_20250216_045034.json
play/network_log_20250216_045236.json
play/network_log_20250216_052021.json
play/network_log_20250216_052222.json
play/network_log_20250216_053037.json
play/network_log_20250216_053242.json
play/network_log_20250216_053625.json
play/network_log_20250216_054027.json
play/network_log_20250216_054341.json
play/README.md
play/requirements.txt
play/web_crawler.py
react_app/.gitignore
react_app/backend/app.py
react_app/Dockerfile
react_app/package.json
react_app/public/index.html
react_app/README.md
react_app/src/App.js
react_app/src/index.js
react_app/src/pages/HomePage.js
react_app/src/pages/VisualizationPage.js
react_app/src/pages/VulnerabilityScanPage.js
react_app/src/recon.json
react_app/src/styles/theme.js
README.md
```

### Dependencies

- lab/frontend/package.json: @emotion/react@^11.10.6, @emotion/styled@^11.10.6, @mui/icons-material@^5.11.16, @mui/material@^5.11.16, @testing-library/jest-dom@^5.16.5, @testing-library/react@^13.4.0, @testing-library/user-event@^13.5.0, axios@^1.3.5, react@^18.2.0, react-dom@^18.2.0, react-router-dom@^6.10.0, react-scripts@5.0.1, web-vitals@^2.1.4
- lab/requirements.txt: Flask@==2.0.1, Flask-CORS@==3.0.10, Flask-Login@==0.5.0, Flask-SQLAlchemy@==2.5.1, Pillow@==9.5.0, PyJWT@==2.3.0, SQLAlchemy@==1.4.23, Werkzeug@==2.0.1
- oracle/backup/requirements.txt: dataclasses@>=0.6, typing@>=3.7.4
- oracle/requirements.txt: openai@>=1.0.0, pandas@>=2.0.0
- play/requirements.txt: playwright@==1.41.2, python-dotenv@==1.0.0
- react_app/package.json: @emotion/react@^11.11.0, @emotion/styled@^11.11.0, @reactflow/node-resizer@^2.2.14, dagre@^0.8.5, framer-motion@^10.12.16, react@^18.2.0, react-dom@^18.2.0, react-router-dom@^6.11.2, react-scripts@5.0.1, reactflow@^11.11.4, socket.io-client@^4.8.1, styled-components@^5.3.10

### Recent commits (newest first)

- Update README.md
- Create README.md
- last commit
- oracle working
- fixing bugs
- fixing bugs
- fixing eslint bugs in package json
- fixing bugs
- fixing bugs
- fix serving static file issue with nginx
- remove ssl to experiment
- add ssl stuff to nginx conf
- a few changes to lab to be able to run it on ubuntu 22.04 server on turwin.tahabiyikli.com
- frontend and backend - react app
- llm stuff WIP
- add frontend code
- move lab stuff to /lab so that we can use this repo for everything else and not just lab
- frontend should not have been a submodule. fixing rn
- lab works! added state management, okay-ish readme (needs review), but overall it's pretty good

## Key source files (fetched from GitHub, selected and truncated for size)

### oracle/requirements.txt

```
pandas>=2.0.0
openai>=1.0.0

```

### play/requirements.txt

```
playwright==1.41.2
python-dotenv==1.0.0

```

### react_app/Dockerfile

```
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 1729

ENV PORT=1729

CMD ["npm", "start"]

```

### lab/requirements.txt

```
Flask==2.0.1
Flask-SQLAlchemy==2.5.1
Flask-Login==0.5.0
Flask-CORS==3.0.10
Werkzeug==2.0.1
SQLAlchemy==1.4.23
Pillow==9.5.0
PyJWT==2.3.0

```

### lab/Dockerfile

```
FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

EXPOSE 1730

CMD ["python", "app.py"]

```

### react_app/package.json

```
{
  "name": "react-app",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "@emotion/react": "^11.11.0",
    "@emotion/styled": "^11.11.0",
    "@reactflow/node-resizer": "^2.2.14",
    "dagre": "^0.8.5",
    "framer-motion": "^10.12.16",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.11.2",
    "reactflow": "^11.11.4",
    "socket.io-client": "^4.8.1",
    "styled-components": "^5.3.10"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "react-scripts": "5.0.1"
  }
}

```

### lab/docker-compose.yml

```yaml
version: '3.8'

services:
  api1:
    build: .
    expose:
      - "1730"
    volumes:
      - ./hospital.db:/app/hospital.db
      - ./uploads:/app/uploads
    environment:
      - FLASK_ENV=production
    restart: unless-stopped

  api2:
    build: .
    expose:
      - "1730"
    volumes:
      - ./hospital.db:/app/hospital.db
      - ./uploads:/app/uploads
    environment:
      - FLASK_ENV=production
    restart: unless-stopped

  api3:
    build: .
    expose:
      - "1730"
    volumes:
      - ./hospital.db:/app/hospital.db
      - ./uploads:/app/uploads
    environment:
      - FLASK_ENV=production
    restart: unless-stopped

  frontend:
    build: 
      context: ./frontend
      dockerfile: Dockerfile
    environment:
      - REACT_APP_API_URL=http://api1.turwin.tahabiyikli.com
      - CI=true
      - DISABLE_ESLINT_PLUGIN=true
    restart: unless-stopped

  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - frontend
      - api1
      - api2
      - api3
    restart: unless-stopped

```

### oracle/backup/requirements.txt

```
dataclasses>=0.6
typing>=3.7.4

```

### lab/frontend/Dockerfile

```
FROM node:18-alpine as builder

WORKDIR /app

# Copy package files
COPY package*.json ./
RUN npm install

# Copy source files
COPY . .

# Build with more verbose output
RUN DISABLE_ESLINT_PLUGIN=true CI=true npm run build && \
    echo "Build complete. Contents of /app/build:" && \
    ls -la /app/build

# Stage 2: Serve
FROM nginx:alpine

# Copy build files and nginx config
COPY --from=builder /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

# Set permissions
RUN chown -R nginx:nginx /usr/share/nginx/html && \
    chmod -R 755 /usr/share/nginx/html && \
    echo "Final contents of /usr/share/nginx/html:" && \
    ls -la /usr/share/nginx/html

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

```

### lab/frontend/package.json

```
{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "proxy": "http://localhost:1730",
  "dependencies": {
    "@emotion/react": "^11.10.6",
    "@emotion/styled": "^11.10.6",
    "@mui/icons-material": "^5.11.16",
    "@mui/material": "^5.11.16",
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "axios": "^1.3.5",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.10.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "DISABLE_ESLINT_PLUGIN=true react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

```

[43 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]