The source code of BACScan: Automatic Black-Box Detection of Broken-Access-Control Vulnerabilities in Web Applications
@inproceedings{liu2025bacscan,
title={BACScan: Automatic Black-Box Detection of Broken-Access-Control Vulnerabilities in Web Applications},
author={Liu, Fengyu and Zhang, Yuan and Li, Enhao and Meng, Wei and Shi, Youkun and Wang, Qianheng and Wang, Chenlin and Lin, Zihan and Yang, Min},
booktitle={Proceedings of the 2025 ACM SIGSAC Conference on Computer and Communications Security},
pages={1320--1333},
year={2025}
}
Install dependencies using uv:
uv syncThis will create a virtual environment and install all required dependencies.
Install Playwright browsers (Chromium):
uv run playwright install chromiumMake sure Elasticsearch is available before crawling and scanning.
nohup ./elasticsearch > ./logs/elasticsearch_log.log 2>&1 &Configure role cookies under ./auth/<cms>/:
user:auth/<cms>/user_nav.jsonadmin:auth/<cms>/admin_nav.jsondet_user:auth/<cms>/user_det.json(used as attacker session in vuln detection)visitordoes not require cookie/session.
Edit target.json (array format):
[
{
"cms": "memos",
"url": "http://10.176.36.21:5231/",
"role": null
}
]role behavior:
nullor omitted: run crawler withvisitor,user,admin"user": run crawler withvisitor+user"admin": run crawler withvisitor+admin- list form is also supported, e.g.
["visitor", "user"]
Run all roles for one target:
[
{
"cms": "memos",
"url": "http://10.176.36.21:5231/",
"role": null
}
]Run visitor + user only:
[
{
"cms": "memos",
"url": "http://10.176.36.21:5231/",
"role": "user"
}
]Run visitor + admin only:
[
{
"cms": "memos",
"url": "http://10.176.36.21:5231/",
"role": "admin"
}
]Multiple targets with explicit role lists:
[
{
"cms": "memos",
"url": "http://10.176.36.21:5231/",
"role": ["visitor", "user"]
},
{
"cms": "xmall",
"url": "http://10.176.36.21:8088/",
"role": ["visitor", "admin"]
}
]Use one command only:
uv run BACScan_start.pyBACScan_start.py orchestrates the full pipeline automatically:
- run crawler for required roles
- merge navigation graph and build dependence
- run vulnerability scan
- Vulnerability results:
result/ - Navigation graphs:
vuln_detection/input/nav_graphs/ - Data dependence construction:
vuln_detection/input/data_dependence/
CSV example (result/result.csv):
cms,vuln_type,attacker_role,victim_role,req_method,req,req_data
memos,horizontal,det_user,user,DELETE,http://10.176.36.21:5231/api/shortcut/215,
memos,horizontal,det_user,user,PATCH,http://10.176.36.21:5231/api/shortcut/215,"{""id"": 215, ""title"": ""AHEPUIgAFF"", ""payload"": ""[]""}"
memos,horizontal,det_user,user,GET,http://10.176.36.21:5231/?shortcutId=206
memos,vertical,det_user,admin,PATCH,http://10.176.36.21:5231/api/memo/1018,"{""id"":1018,""content"":""asaasas"",""visibility"":""PRIVATE"",""resourceIdList"":[]}"File location:
vuln_detection/input/nav_graphs/<cms>/visitor_navigraph.jsonvuln_detection/input/nav_graphs/<cms>/user_navigraph.jsonvuln_detection/input/nav_graphs/<cms>/admin_navigraph.json
Node example:
{
"USER|GET|http://10.176.36.21:5231/|q:tag": {
"method": "GET",
"req_url": "http://10.176.36.21:5231/?tag=asa",
"role": "user",
"public": false,
"edges": [
"USER|GET|http://10.176.36.21:5231/|q:tag,text"
]
}
}File location:
vuln_detection/input/data_dependence/<cms>.json
Example (operation_node -> dependent_get_nodes):
{
"USER|POST|http://10.176.36.21:5231/api/memo|b:content,visibility|ct:json": [
"USER|GET|http://10.176.36.21:5231/|q:tag",
"USER|GET|http://10.176.36.21:5231/|q:text"
]
}Use this script only when crawler missed a request and you already have the raw HTTP request text.
- Optional: set CMS:
$env:BACSCAN_CMS="xmall"- Edit
add_node.py:
- set
role(visitor/user/admin) - set
request_textto the full raw HTTP request
- Run:
uv run add_node.py