Security
Because the Sparo tool acts as a wrapper for Git, our goal is to provide comparable security expectations as the git
command.
⚠️ This is a goal not a guarantee. ⚠️
The software is still in its early stages of development, and not all security requirements have been identified or implemented yet. Efforts to improve Sparo security should not be interpreted to contradict the terms of the MIT license:
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Security scenarios
Git doesn't provide a formal security specification, so to facilitate analysis of Sparo contributions, we've identified usage scenarios that imply security requirements. We welcome your feedback -- please let us know if we've overlooked an important use case or if Git does not behave as described.
SS1: Safely clone an untrusted repo
Suppose that an unfamiliar remote Git repository contains malicious files, which includes malicious config files such as .gitattributes
, .gitignore
, and Git hook scripts. The following operations are expected to be safe:
- Using
git clone
to clone the remote repo. - Using
git checkout
to checkout files. - Using
git commit
to commit modifications of local files.
Git ensures safety by ignoring Git hooks and .gitattributes
filters by default. The user must explicitly run a command to "opt-in", signifying their trust that the repository is free from malicious code. For example, invoking rush install
will register predefined Git hooks, because NPM installation involves executing untrusted scripts and therefore signifies trust in the cloned repository. As another example, if .gitattributes
references the LFS filter, the user must first opt-in by running git lfs install
, signifying their trust that the filter author has implemented security protections against malicious inputs for that filter.
Sparo introduces additional config files such as <profile-name>.json. Parsing of these config files must also treat the inputs as potentially malicious, and provide the same guarantees.
SS2: Safely clone an untrusted repository parameter
A command such as git clone https://github.com/example/project.git
will write into a subfolder called project
. The Git documentation calls this the "humanish" portion of the URL.
Consider a remote service that receives the REPOSITORY
parameter as a text string and then invokes git clone REPOSITORY
with correct shell-escaping of the parameter. In calculating the humanish folder name, Git should not incorporate special characters such as ..
or /
that would cause the operation to write cloned files outside of the intended folder.
And of course, if an explicit target folder is specified using git clone https://github.com/example/project.git my-folder
, then no files should be cloned outside of the my-folder
folder.
SS3: Git parameters may include special characters
Shell interpreters commonly transform expressions involving special characters such as $
, %
, (
, etc. For example:
# Problem: Bash would replace "$project" with the value of
# the environment variable whose name is "project".
git clone https://github.com/example/project.git $project
This requires escaping:
# This backslash escape ensures that a literal dollar sign
# is included in the created folder name:
git clone https://github.com/example/project.git \$project
When the sparo
command-line invokes subprocesses such as git
, it must carefully ensure that process arguments are correctly escaped to avoid being transformed by the shell. For example, if \$project
gets expanded by the shell during subprocess invocation, the escaping will be defeated, which could be exploited to circumvent the other Sparo security guarantees. If certain characters cannot be safely escaped by Node.js, they should be rejected with an error message.
Security assumptions
It's also useful to point out aspects that are NOT expected to be secure.
Assumption: Shell environment variables are trusted
For the most part, the git
CLI assumes that the shell environment variables are trusted. For example, it relies on the PATH
variable to discover the location of the ssh
binary, and most of the parent process's variables are passed through to child processes.
Because Sparo the tool is invoked by the Node.js runtime, arbitrary code execution is possible via environment variables such as NODE_OPTIONS.
Assumption: Command line is generally trusted
The git
command-line accepts parameters such as -c which can trigger execution of arbitrary code. Therefore in general, we assume that the command-line parameters are trusted. However, certain parameters can provide stricter guarantees, for example the <repository>
argument for git clone
mentioned in SS3.
Assumption: Commands may consume excessive resources
Commands such as git clone
may consume an arbitrary amount of disk space or take arbitrarily long to complete. In general, denial-of-service attacks are not considered an important risk for this type of development tool.
Assumption: STDOUT and STDERR may contain arbitrary characters
When invoking the git
CLI, the console output may include strings printed by hook scripts or other shell commands. These strings may contain special characters that are unsafe to embed in other contexts such as an HTML document or SQL string literal. It is the responsibility of the calling processes to correctly escape any STDOUT or STDERR output produced by the git
or sparo
process.