zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

unsafe_exec.ex (2000B)


      1 defmodule Credo.Check.Warning.UnsafeExec do
      2   use Credo.Check,
      3     base_priority: :high,
      4     category: :warning,
      5     explanations: [
      6       check: """
      7       Spawning external commands can lead to command injection vulnerabilities.
      8 
      9       Use a safe API where arguments are passed as an explicit list, rather
     10       than unsafe APIs that run a shell to parse the arguments from a single
     11       string.
     12 
     13       Safe APIs include:
     14 
     15         * `System.cmd/2,3`
     16         * `:erlang.open_port/2`, passing `{:spawn_executable, file_name}` as the
     17           first parameter, and any arguments using the `:args` option
     18 
     19       Unsafe APIs include:
     20 
     21         * `:os.cmd/1,2`
     22         * `:erlang.open_port/2`, passing `{:spawn, command}` as the first
     23           parameter
     24 
     25       """
     26     ]
     27 
     28   @doc false
     29   @impl true
     30   def run(%SourceFile{} = source_file, params \\ []) do
     31     issue_meta = IssueMeta.for(source_file, params)
     32 
     33     Credo.Code.prewalk(source_file, &traverse(&1, &2, issue_meta))
     34   end
     35 
     36   defp traverse({{:., _loc, call}, meta, args} = ast, issues, issue_meta) do
     37     case get_forbidden_call(call, args) do
     38       {bad, suggestion} ->
     39         {ast, issues_for_call(bad, suggestion, meta, issue_meta, issues)}
     40 
     41       nil ->
     42         {ast, issues}
     43     end
     44   end
     45 
     46   defp traverse(ast, issues, _issue_meta) do
     47     {ast, issues}
     48   end
     49 
     50   defp get_forbidden_call([:os, :cmd], [_]) do
     51     {":os.cmd/1", "System.cmd/2,3"}
     52   end
     53 
     54   defp get_forbidden_call([:os, :cmd], [_, _]) do
     55     {":os.cmd/2", "System.cmd/2,3"}
     56   end
     57 
     58   defp get_forbidden_call([:erlang, :open_port], [{:spawn, _}, _]) do
     59     {":erlang.open_port/2 with `:spawn`", ":erlang.open_port/2 with `:spawn_executable`"}
     60   end
     61 
     62   defp get_forbidden_call(_, _) do
     63     nil
     64   end
     65 
     66   defp issues_for_call(call, suggestion, meta, issue_meta, issues) do
     67     options = [
     68       message: "Prefer #{suggestion} over #{call} to prevent command injection",
     69       trigger: call,
     70       line_no: meta[:line]
     71     ]
     72 
     73     [format_issue(issue_meta, options) | issues]
     74   end
     75 end