Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(security): sanitize paths and prevent shell scripts #33

Merged
merged 1 commit into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
[ci-image]: https://img.shields.io/github/actions/workflow/status/wellwelwel/poku/ci.yml?event=push&style=flat&label=CI&branch=main
[ql-url]: https://github.com/wellwelwel/poku/actions/workflows/codeql.yml?query=branch%3Amain
[ql-image]: https://img.shields.io/github/actions/workflow/status/wellwelwel/poku/codeql.yml?event=push&style=flat&label=Code%20QL&branch=main
[license-url]: https://github.com/wellwelwel/poku/blob/main/LICENSE
[license-image]: https://img.shields.io/npm/l/poku.svg?maxAge=2592000&color=9c88ff

# Poku

Expand All @@ -23,6 +25,7 @@
[![TypeScript Version][typescript-version-image]][typescript-url]
[![GitHub Workflow Status (with event)][ci-image]][ci-url]
[![GitHub Workflow Status (with event)][ql-image]][ql-url]
[![License][license-image]][license-url]

Enjoying **Poku**? Consider giving him a star ⭐️

Expand Down Expand Up @@ -184,10 +187,22 @@ I'm continuously working to improve **Poku**. If you've got something interestin

## Acknowledgements

- [**Contributors**](https://github.com/wellwelwel/poku/graphs/contributors)
- [**Contributors**](https://github.com/wellwelwel/poku/graphs/contributors).

---

## Contributing

Please check the [_CONTRIBUTING.md_](./CONTRIBUTING.md) for instructions 🚀
Please check the [**CONTRIBUTING.md**](./CONTRIBUTING.md) for instructions 🚀

---

## License

Poku is under the [**MIT** License](./LICENSE).

---

## Security Policy

Please check the [**SECURITY.md**](./SECURITY.md) and the section [**Is Poku Safe?**](https://poku.dev/docs/security) from Documentation.
27 changes: 22 additions & 5 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Security Policy

## Is Poku Safe?

**Poku** is an open-source project, so you can see both the [Source Code on **GitHub** Repository](https://github.com/wellwelwel/poku) and the [Distribution Code on **NPM**](https://www.npmjs.com/package/poku?activeTab=code).

### Why does Poku use `child_process`?

Some test runners use **`eval`**, **Poku** prefers to use **`spawn`** to create a isolated process securely for each test file.

---

## Protective Measures

See the [**Protective Measures**](https://poku.dev/docs/security#protective-measures) in the documentation.

---

## Supported Versions

Currently, security updates will be applied to the following versions of **Poku**:
Expand All @@ -9,17 +25,18 @@ Currently, security updates will be applied to the following versions of **Poku*
| 1.x.x | :white_check_mark: |
| 0.x.x | :x: |

## Reporting a Vulnerability
---

> **Please, give Detailed Reports**
## Reporting a Vulnerability

- Please, give detailed reports
- Include steps to reproduce the vulnerability, and if possible, a patch or workaround.
- Include the specific version of **Poku** you are using.

Please report it privately: https://github.com/wellwelwel/poku/security/advisories.

---
- Once the issue has been resolved, you will be attributed a part of the report.

> If you wish it, once the issue has been resolved, you will be attributed a part of the report.
---

Let's keeping **Poku** safe 🩵
Let's keeping **Poku** safe 🐷
16 changes: 13 additions & 3 deletions src/modules/list-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ import fs from 'node:fs';
import path from 'node:path';
import type { Configs } from '../@types/list-files.js';

export const sanitizePath = (input: string, ensureTarget?: boolean): string => {
const sanitizedPath = input
.replace(/[/\\]+/g, path.sep) // adapting slashes according to OS
.replace(/(\.\.(\/|\\|$))+/g, '') // ensure the current path level
.replace(/[<>:|^?*]+/g, ''); // removing unusual path characters

// Preventing absolute path access
return ensureTarget ? sanitizedPath.replace(/^[/\\]/, './') : sanitizedPath;
};

export const escapeRegExp = (string: string) =>
string.replace(/[.*{}[\]\\]/g, '\\$&');

Expand All @@ -15,7 +25,7 @@ export const listFiles = (
files: string[] = [],
configs?: Configs
) => {
const currentFiles = fs.readdirSync(dirPath);
const currentFiles = fs.readdirSync(sanitizePath(dirPath));
const defaultRegExp = /\.(test|spec)\./i;
const filter: RegExp =
(envFilter
Expand All @@ -31,7 +41,7 @@ export const listFiles = (
: undefined;

for (const file of currentFiles) {
const fullPath = path.join(dirPath, file);
const fullPath = sanitizePath(path.join(dirPath, file));

if (/node_modules/.test(fullPath)) continue;
if (exclude && exclude.some((regex) => regex.test(fullPath))) continue;
Expand All @@ -45,4 +55,4 @@ export const listFiles = (
};

export const publicListFiles = (targetDir: string, configs?: Configs) =>
listFiles(targetDir, [], configs);
listFiles(sanitizePath(targetDir), [], configs);
1 change: 1 addition & 0 deletions src/services/run-test-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export const runTestFile = (

const child = spawn(runtime!, runtimeArguments, {
stdio: ['inherit', 'pipe', 'pipe'],
shell: false,
env: {
...process.env,
FILE: configs?.parallel ? fileRelative : '',
Expand Down
4 changes: 2 additions & 2 deletions src/services/run-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { EOL } from 'node:os';
import path from 'node:path';
import { runner } from '../helpers/runner.js';
import { indentation } from '../helpers/indentation.js';
import { listFiles } from '../modules/list-files.js';
import { listFiles, sanitizePath } from '../modules/list-files.js';
import { hr } from '../helpers/hr.js';
import { format } from '../helpers/format.js';
import { runTestFile } from './run-test-file.js';
Expand All @@ -20,7 +20,7 @@ export const runTests = async (
configs?: Configs
): Promise<boolean> => {
const cwd = process.cwd();
const testDir = path.join(cwd, dir);
const testDir = path.join(cwd, sanitizePath(dir));
const currentDir = path.relative(cwd, testDir);
const files = listFiles(testDir, undefined, configs);
const totalTests = files.length;
Expand Down
8 changes: 0 additions & 8 deletions website/docs/examples/back-to-the-roots/_category_.json

This file was deleted.

2 changes: 2 additions & 0 deletions website/docs/examples/beforeEach.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ node ./test/run.test.js

> Or `npx tsx ./test/run.test.ts` for **TypeScript**.

<hr />

:::tip
**Poku**'s `assert` will use the message exactly as it is when using `describe` or `it`. <br />
Your **Poku** is waiting for you 🐷✨
Expand Down
36 changes: 23 additions & 13 deletions website/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,25 +51,23 @@ Enjoying **Poku**? Consider giving him a star ⭐️

## Why Poku?

Don't worry about `describe`, `it`, `beforeEach` and everything else 🚀

> You don't need to learn what you already know ✨

<div className='features black'>
<p>
<Success />
<span>Designed to be highly intuitive</span>
</p>
<p>
<Success />
<span>No constraints or rules, code in your own signature style</span>
<span>You don't need to learn what you already know ✨</span>
</p>
<p>
<Success />
<Link to='/'>Compare Poku with the Most Popular Test Runners</Link>
<span>
Don't worry about `describe`, `it`, `beforeEach` and everything else 🚀
</span>
</p>
</div>

<br />

- [**Compare Poku with the Most Popular Test Runners 🧪**](/docs/comparing)

<hr />

## **Install**
Expand Down Expand Up @@ -174,7 +172,7 @@ deno run npm:poku targetDir

## Documentation

> Initially, the [documentation](/docs/category/documentation) is based on **Node.js** usage, but you can use all the options normally for both **Bun** and **Deno**.
> Initially, the [**documentation**](/docs/category/documentation) and [**examples**](/docs/category/examples) are based on **Node.js** usage, but you can use all the options normally for both **Bun** and **Deno**.

<hr />

Expand All @@ -186,10 +184,22 @@ I'm continuously working to improve **Poku**. If you've got something interestin

## Acknowledgements

- [**Contributors**](https://github.com/wellwelwel/poku/graphs/contributors)
- [**Contributors**](https://github.com/wellwelwel/poku/graphs/contributors).

<hr />

## Contributing

Please check the [_CONTRIBUTING.md_](https://github.com/wellwelwel/poku/blob/main/CONTRIBUTING.md) for instructions 🚀
Please check the [**CONTRIBUTING.md**](https://github.com/wellwelwel/poku/blob/main/CONTRIBUTING.md) for instructions 🚀

<hr />

## License

Poku is under the [**MIT License**](https://github.com/wellwelwel/poku/blob/main/LICENSE).

<hr />

## Security Policy

Please check the [**SECURITY.md**](https://github.com/wellwelwel/poku/blob/main/SECURITY.md) and the section [**Is Poku Safe?**](/docs/security) from Documentation.
26 changes: 26 additions & 0 deletions website/docs/security.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Is Poku Safe?

**Poku** is an open-source project, so you can see both the [Source Code on **GitHub** Repository](https://github.com/wellwelwel/poku) and the [Distribution Code on **NPM**](https://www.npmjs.com/package/poku?activeTab=code).

## Why does Poku use `child_process`?

Some test runners use **`eval`**, **Poku** prefers to use **`spawn`** to create a isolated process securely for each test file.

## Protective Measures

- Blocks access above target directory by filtering `../` and `/` paths, for example:
- `/root` will be sanitized to `./root`
- `../../etc/secret` will be sanitized to `./etc/secret`
- Normalizes paths according to the OS, allowing all collaborators to use the same path, each using their own OS:
- `\` for **Windows**
- `/` for **Linux** and **macOS**
- Normalizes paths by filtering unusual path characters, for example:
- `<>:|^?*`
- Prevents shell scripts by setting `shell` to `false` in **`spawn`** options, ensuring that only secure arguments will be used.
- Every **RegExp** is prev-tested using the [**ReDoS Checker**](https://devina.io/redos-checker).

## Security Policy

:::info
See the [**Security Policy** on **GitHub** repository](https://github.com/wellwelwel/poku/blob/main/SECURITY.md).
:::
1 change: 1 addition & 0 deletions website/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const sidebars: SidebarsConfig = {
'index',
'comparing',
'overview',
'security',
{
type: 'category',
label: 'Documentation',
Expand Down
3 changes: 1 addition & 2 deletions website/src/css/custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

[data-theme] {
blockquote {
font-size: 0.95rem;
font-size: 0.875rem;
}
}

Expand Down Expand Up @@ -131,7 +131,6 @@ html[data-theme='dark'] {
color: #b9bfdc;

blockquote {
font-size: 13px;
color: #8188ab;
}

Expand Down
Loading