⚠️ Important security notice

Be careful when writing regexes. Try to ensure no malicious input could be injected in your regexes. It's better if your actions are direct commands, and not inline shell scripts.

If you use products of regexes in shell scripts, double-check that all user input is correctly escaped. Make use of tools like shellcheck to analyze your code.

Avoid using this kind of commands that mix code and user input:

['sh', '-c', 'mycommand <pattern>']

Example of a configuration permitting remote execution:

insecure.jsonnet

{
  patterns: {
    user: {
      regex: @'.*',
    },
  },
  streams: {
    myservice: {
      cmd: ['tail', '-f', '/tmp/reaction-example'],
      filters: {
        myfilter: {
          regex: [
            @'Connection of <user> failed',
          ],
          // [...]
          actions: {
            myaction: {
              cmd: ['sh', '-c', 'echo "<user>"'],
            },
          },
        },
      },
    },
  },
}

Let's launch reaction in one terminal:

$ touch /tmp/reaction-example
$ reaction start -c insecure.jsonnet

Then let's append malicious data to the tailed file in another terminal:

$ echo 'Connection of "; mkdir malicious-directory" failed' >> /tmp/reaction-example

We simulated an attacker supplying "; mkdir malicious-directory" as a username in a random service which doesn't check for non-alphanumeric characters in its usernames.

reaction will then launch the command:

myaction: {
  cmd: ['sh', '-c', 'echo "<user>"'],
},

Substituting <user> with the malicious input:

['sh', '-c', 'echo ""; mkdir malicious-directory""']

Of course, here it's a mkdir but it can be anything.

IP pattern

Starting with reaction v2.2.0, patterns of type ip, can be specified. The regex is provided by reaction and is guaranteed to contain only those characters: 0123456789.:.

Those characters have no special meaning in sh, so having an sh -c ... <ip> should be safe.

Example

Let's take a common example: Appending a line to a file.

Problematic command

actions: {
  problematic: {
    cmd: [ 'sh', '-c', 'echo "<name>" >> /tmp/file' ],
  },
}
actions:
  problematic:
    cmd: [ 'sh', '-c', 'echo "<name>" >> /tmp/file' ]

Bash solution

actions: {
  bash: {
    cmd: [ 'sh', '/append.sh', '<name>' ],
  },
}
actions:
  bash:
    cmd: [ 'sh', '/append.sh', '<name>' ]

/append.sh:

echo "$1" >> /tmp/file

Python inline solution

Python supports inline scripts separated from user input.

actions: {
  python: {
    cmd: [
      'python',
      '-c',
      'import sys; open("/tmp/file", "a+").write(sys.argv[1] + "\n")',
      '<name>'
    ],
  },
}
actions:
  python:
    cmd:
      - 'python'
      - '-c'
      - 'import sys; open("/tmp/file", "a+").write(sys.argv[1] + "\n")'
      - '<name>'

Summary

Regexes are powerful, and need to be carefully written. Avoid having too permissive regexes capturing user input.

When executing scripts in actions, code and user input must be clearly separated.

Save scripts in files and call them ['bash', '/path/to/script', 'arg1', '...'] instead of having inline ['bash', '-c', 'command arg1 && command arg2'] when dealing with user input.