You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
# Command Injection Reproduction Notes for faucet_server.js - #1749
Hello,
I am writing to report a potential OS Command Injection vulnerability in the following file: deployment/docker/localsecret/faucet/faucet_server.js
The issue appears when the address query parameter of the /faucet endpoint is passed as the destination address into send_command(), which concatenates it into a shell command string that is later executed via child_process.exec(...). Under certain conditions, a specially crafted address value containing shell metacharacters (such as &, |, or ;) may allow unintended command execution on the host system. This poses a significant security risk as it allows for unauthenticated Remote Code Execution (RCE) on the faucet host.
Root Cause
The issue is caused by unsafe shell command construction in the following function:
dest_address is attacker-controlled (address), and because exec(...) runs the command through the system shell, any shell metacharacters present in it are interpreted as command syntax rather than literal text:
A minimal reproduction script is provided in: poc_faucet_server.js poc_faucet_server.js
This Proof of Concept (PoC) is intended to demonstrate that external input can reach dangerous command execution logic through the vulnerable code path.
What the PoC Does
The PoC performs a minimal end-to-end trigger of the vulnerable code path:
It hooks child_process.exec to log intercepted commands before they execute.
It stubs http so the request handler can be captured without binding a port.
It loads faucet_server.js.
It invokes the request handler with a crafted URL: /faucet?address=x%20%26%20calc, i.e. address = "x & calc".
This causes the application to build secretd tx bank send <src> <address> <amount><DENOM> --from ... -y, where & is interpreted as a command separator and calc is executed as a second command.
In the provided example, the injected payload is crafted so that successful command execution launches the Calculator application. This serves as a visible indicator that external input can reach the OS command execution sink without proper sanitization.
Example Payload
The PoC uses the following payload for the address query parameter:
x & calc
How to Run
Run from the folder containing the files:
node poc_faucet_server.js
Expected Output
When the PoC runs, you should see output similar to:
[POC] Sending request: /faucet?address=x%20%26%20calc
[POC] child_process.exec() would run:
>> COMMAND: secretd keys list
[POC] child_process.exec() would run:
>> COMMAND: secretd tx bank send secret1faucetaddress000000000000000000000 x & calc 1000000000uscrt --from a --gas-prices 0.25uscrt -y
[POC] >>> INJECTION CONFIRMED: "calc" reached the shell command
[POC] Executing the command for real ...
[POC] status: 200
[POC] response body: {"txhash":"POC_TXHASH"}
[POC] The injection instruction has been delivered to the operating system
In the vulnerable version, when the crafted address is processed, the shell interprets the & metacharacter and executes the injected calc command, launching the Calculator application as a benign demonstration effect.
This shows that the attacker-controlled address value can influence command execution behavior through the vulnerable send_command() path.
Patch Explanation
This branch also includes a patched version of faucet_server.js (new_faucet_server.js) intended to mitigate the command injection risk described above.
What the patch changes
The patch replaces child_process.exec() — which runs the command through a shell — with child_process.execFile(), which executes the program directly and passes each argument as a separate array element. This preserves the original behaviour (query the key list, send coins from the faucet) while ensuring address is never interpreted as shell syntax.
Validation introduced by the patch
execShellCommand now takes the program and its arguments separately, and callers build explicit argument arrays:
Because execFile does not invoke a shell, shell metacharacters such as &, |, ;, $(), and ` in address are treated as literal characters rather than command syntax. A value such as x & calc is delivered to secretd as a single literal argument and no second calc command is executed, while legitimate addresses continue to work as expected.
Command Injection Reproduction Notes for faucet_server.js
Summary
Hello,
I am writing to report a potential OS Command Injection vulnerability in the following file: scripts/faucet/faucet_server.js
The issue appears when the address query parameter of the /faucet endpoint is passed as the destination address into send_command(), which concatenates it into a shell command string that is later executed via child_process.exec(...). Under certain conditions, a specially crafted address value containing shell metacharacters (such as &, |, or ;) may allow unintended command execution on the host system. This poses a significant security risk as it allows for unauthenticated Remote Code Execution (RCE) on the faucet host.
Root Cause
The issue is caused by unsafe shell command construction in the following function:
dest_address is attacker-controlled (address), and because exec(...) runs the command through the system shell, any shell metacharacters present in it are interpreted as command syntax rather than literal text:
A minimal reproduction script is provided in: poc_faucet_server.js poc_faucet_server.js
This Proof of Concept (PoC) is intended to demonstrate that external input can reach dangerous command execution logic through the vulnerable code path.
What the PoC Does
The PoC performs a minimal end-to-end trigger of the vulnerable code path:
It hooks child_process.exec to log intercepted commands before they execute.
It stubs http so the request handler can be captured without binding a port.
It loads faucet_server.js.
It invokes the request handler with a crafted URL: /faucet?address=x%20%26%20calc%20%26, i.e. address = "x & calc &".
This causes the application to build secretd tx bank send <src> <address> <amount><DENOM> --from ... -y 2> /dev/null, where & is interpreted as a command separator and calc is executed as a second command.
In the provided example, the injected payload is crafted so that successful command execution launches the Calculator application. This serves as a visible indicator that external input can reach the OS command execution sink without proper sanitization.
Example Payload
The PoC uses the following payload for the address query parameter:
x & calc &
How to Run
Run from the folder containing the files:
node poc_faucet_server.js
Expected Output
When the PoC runs, you should see output similar to:
[POC] Sending request: /faucet?address=x%20%26%20calc%20%26
[POC] child_process.exec() would run:
>> COMMAND: secretd keys list --output json 2> /dev/null
[POC] child_process.exec() would run:
>> COMMAND: secretd tx bank send secret1faucetaddress000000000000000000000 x & calc & 1000000000uscrt --from a --gas-prices 0.25uscrt -y 2> /dev/null
[POC] >>> INJECTION CONFIRMED: "calc" reached the shell command
[POC] Executing the command for real ...
[POC] status: 200
[POC] response body: {"txhash":"POC_TXHASH"}
[POC] The injection instruction has been delivered to the operating system
In the vulnerable version, when the crafted address is processed, the shell interprets the & metacharacter and executes the injected calc command, launching the Calculator application as a benign demonstration effect.
This shows that the attacker-controlled address value can influence command execution behavior through the vulnerable send_command() path.
Patch Explanation
This branch also includes a patched version of faucet_server.js (new_faucet_server.js) intended to mitigate the command injection risk described above.
What the patch changes
The patch replaces child_process.exec() — which runs the command through a shell — with child_process.execFile(), which executes the program directly and passes each argument as a separate array element. This preserves the original behaviour (query the key list, send coins from the faucet) while ensuring address is never interpreted as shell syntax.
Because execFile does not use a shell, the 2> /dev/null redirection in the original commands cannot be expressed as a shell operator. Its effect (stderr being ignored) is preserved by simply not acting on stderr in the callback — the original code already neutralised its own else if (stderr) branch via that redirection.
Validation introduced by the patch
execShellCommand now takes the program and its arguments separately, and callers build explicit argument arrays:
constexecFile=require("child_process").execFile;functionexecShellCommand(cmd,args=[]){returnnewPromise((resolve,reject)=>{execFile(cmd,args,(error,stdout)=>{if(error){reject(error);}else{resolve(JSON.parse(stdout));// stderr is ignored (see note above)}});});}asyncfunctionsend_command(src_key_name,src_address,dest_address,amount){constsend_args=["tx","bank","send",src_address,dest_address,`${amount}${DENOM}`,"--from",src_key_name,"--gas-prices","0.25uscrt","-y",];constresult=awaitexecShellCommand("secretd",send_args);returnresult.txhash;}
Because execFile does not invoke a shell, shell metacharacters such as &, |, ;, $(), and ` in address are treated as literal characters rather than command syntax. A value such as x & calc & is delivered to secretd as a single literal argument and no second calc command is executed, while legitimate addresses continue to work as expected.
This branch has not been deployed
No deployments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Hello,
I am writing to report a potential OS Command Injection vulnerability in the following file:
deployment/docker/localsecret/faucet/faucet_server.jsThe issue appears when the
addressquery parameter of the/faucetendpoint is passed as the destination address intosend_command(), which concatenates it into a shell command string that is later executed viachild_process.exec(...). Under certain conditions, a specially craftedaddressvalue containing shell metacharacters (such as&,|, or;) may allow unintended command execution on the host system. This poses a significant security risk as it allows for unauthenticated Remote Code Execution (RCE) on the faucet host.Root Cause
The issue is caused by unsafe shell command construction in the following function:
dest_addressis attacker-controlled (address), and becauseexec(...)runs the command through the system shell, any shell metacharacters present in it are interpreted as command syntax rather than literal text:Reproduction Material
A minimal reproduction script is provided in:
poc_faucet_server.jspoc_faucet_server.js
This Proof of Concept (PoC) is intended to demonstrate that external input can reach dangerous command execution logic through the vulnerable code path.
What the PoC Does
The PoC performs a minimal end-to-end trigger of the vulnerable code path:
child_process.execto log intercepted commands before they execute.httpso the request handler can be captured without binding a port.faucet_server.js./faucet?address=x%20%26%20calc, i.e.address = "x & calc".secretd tx bank send <src> <address> <amount><DENOM> --from ... -y, where&is interpreted as a command separator andcalcis executed as a second command.In the provided example, the injected payload is crafted so that successful command execution launches the Calculator application. This serves as a visible indicator that external input can reach the OS command execution sink without proper sanitization.
Example Payload
The PoC uses the following payload for the
addressquery parameter:x & calcHow to Run
Run from the folder containing the files:
Expected Output
When the PoC runs, you should see output similar to:
In the vulnerable version, when the crafted address is processed, the shell interprets the
&metacharacter and executes the injectedcalccommand, launching the Calculator application as a benign demonstration effect.This shows that the attacker-controlled
addressvalue can influence command execution behavior through the vulnerablesend_command()path.Patch Explanation
This branch also includes a patched version of
faucet_server.js(new_faucet_server.js) intended to mitigate the command injection risk described above.What the patch changes
The patch replaces
child_process.exec()— which runs the command through a shell — withchild_process.execFile(), which executes the program directly and passes each argument as a separate array element. This preserves the original behaviour (query the key list, send coins from the faucet) while ensuringaddressis never interpreted as shell syntax.Validation introduced by the patch
execShellCommandnow takes the program and its arguments separately, and callers build explicit argument arrays:Because
execFiledoes not invoke a shell, shell metacharacters such as&,|,;,$(), and`inaddressare treated as literal characters rather than command syntax. A value such asx & calcis delivered tosecretdas a single literal argument and no secondcalccommand is executed, while legitimate addresses continue to work as expected.