karnel-termux 4.17.9 → 4.17.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  <p align="center">
10
10
  <a href="https://github.com/israelmarques1024-dotcom/karnel-termux">
11
- <img src="https://img.shields.io/badge/version-4.17.9-0078D4?style=for-the-badge" alt="Version">
11
+ <img src="https://img.shields.io/badge/version-4.17.10-0078D4?style=for-the-badge" alt="Version">
12
12
  </a>
13
13
  <a href="https://www.npmjs.com/package/karnel-termux">
14
14
  <img src="https://img.shields.io/npm/v/karnel-termux?style=for-the-badge&logo=npm&color=cb3837" alt="npm">
@@ -22,8 +22,8 @@
22
22
  <a href="https://termux.dev/">
23
23
  <img src="https://img.shields.io/badge/platform-Termux%20%7C%20Android-0078D4?style=for-the-badge" alt="Platform">
24
24
  </a>
25
- <a href="https://karneltermux.vercel.app">
26
- <img src="https://img.shields.io/badge/Site-karneltermux.vercel.app-0078D4?style=for-the-badge" alt="Website">
25
+ <a href="https://israelmarques1024-dotcom.github.io/karnel-termux">
26
+ <img src="https://img.shields.io/badge/Site-karneltermux.github.io-0078D4?style=for-the-badge" alt="Website">
27
27
  </a>
28
28
  </p>
29
29
 
@@ -61,7 +61,7 @@ Core agent contributions by **devcorex**.
61
61
  ### Via checksummed GitHub release (recommended)
62
62
 
63
63
  ```bash
64
- version=4.17.9
64
+ version=4.17.10
65
65
  tmpdir=$(mktemp -d) && trap 'rm -rf "$tmpdir"' EXIT
66
66
  base="https://github.com/israelmarques1024-dotcom/karnel-termux/releases/download/v$version"
67
67
  curl -fsSL "$base/karnel-termux-install.sh" -o "$tmpdir/karnel-termux-install.sh"
@@ -507,7 +507,7 @@ karnel open ai # Open AI module docs
507
507
  karnel open db # Open DB module docs
508
508
  ```
509
509
 
510
- Documentation loads from https://karneltermux.vercel.app.
510
+ Documentation loads from https://israelmarques1024-dotcom.github.io/karnel-termux.
511
511
 
512
512
  ---
513
513
 
@@ -519,7 +519,7 @@ Documentation loads from https://karneltermux.vercel.app.
519
519
  - [Troubleshooting](docs/troubleshooting/index.md)
520
520
  - [Architecture](docs/ARCHITECTURE/index.md)
521
521
  - [Documentation changelog](docs/CHANGELOG.md)
522
- - [Official website](https://karneltermux.vercel.app)
522
+ - [Official website](https://israelmarques1024-dotcom.github.io/karnel-termux)
523
523
 
524
524
  ---
525
525
 
@@ -651,7 +651,7 @@ MIT © Israel Marques
651
651
  ---
652
652
 
653
653
  <p align="center">
654
- <a href="https://karneltermux.vercel.app">
654
+ <a href="https://israelmarques1024-dotcom.github.io/karnel-termux">
655
655
  <img src="https://img.shields.io/badge/Full%20Documentation-0078D4?style=for-the-badge" alt="Documentation">
656
656
  </a>
657
657
  <a href="https://www.youtube.com/@capideb">
@@ -1,3 +1,9 @@
1
+ ---
2
+ title: Architecture
3
+ permalink: /ARCHITECTURE/
4
+ layout: base
5
+ ---
6
+
1
7
  # Karnel Architecture
2
8
 
3
9
  ## Project Structure
package/docs/CHANGELOG.md CHANGED
@@ -1,10 +1,36 @@
1
1
  ---
2
2
  title: Documentation Changelog
3
3
  permalink: /CHANGELOG/
4
+ layout: base
4
5
  ---
5
6
 
6
7
  # Documentation Changelog
7
8
 
9
+ ## 4.17.10
10
+
11
+ - Round 10 security/correctness hardening (23 distinct fixes):
12
+ - **Termux `/tmp` fallbacks eliminated** across host-side code
13
+ (`update.sh`, `brain.sh`, `version.sh`, `log.sh`, `agent_actions.sh`,
14
+ `doctor/code_langs.sh`, `supabase`, and the `security/*` tools amass,
15
+ subfinder, ffuf, gobuster, burpsuite, zap) — now use `KARNEL_CACHE`.
16
+ - **`karnel show <module>`** now rejects invalid module names
17
+ (`/`, `..`, `~`), closing a path-traversal / information-disclosure bug.
18
+ - **Agent PLAN (read-only) mode** hardened: blocks `sed`/`awk`/`perl`/
19
+ `xargs`/`make`/`env`/`nohup`/`setsid`, `sed`/`perl -i`, editors,
20
+ `git apply`/`worktree`/`read-tree`/`update-index`, and now also catches
21
+ redirections without a preceding space (`echo x>file`).
22
+ - **Plugin supply chain** fail-closed: installs now require a manifest
23
+ checksum (was silently skipped), and registry installs pin to a committed
24
+ SHA when provided.
25
+ - **`karnel pg backup --schedule`** no longer swallows `crontab` failures
26
+ and uses the escaped DB name to avoid duplicate cron jobs.
27
+ - **Reinstall** now proceeds to install when the uninstall step reports
28
+ "already uninstalled" (rc 2) instead of aborting.
29
+ - **Archive extraction hardened**: `cline`, `goose`, `kiro` AI installers
30
+ and `zork` now use the safe extractors; `zork` also drops literal `/tmp`.
31
+ - Site fully overhauled (navigation, dark mode, GitHub Pages URLs, Liquid
32
+ fixes, consistent front matter).
33
+
8
34
  ## 4.17.9
9
35
 
10
36
  - Hardened installer and runtime security across the toolkit:
@@ -0,0 +1,15 @@
1
+ ---
2
+ layout: default
3
+ ---
4
+
5
+ <nav class="site-nav" aria-label="Documentation">
6
+ <a href="{{ '/' | relative_url }}">Docs</a>
7
+ <a href="{{ '/cli/' | relative_url }}">CLI</a>
8
+ <a href="{{ '/doctor/' | relative_url }}">Doctor</a>
9
+ <a href="{{ '/troubleshooting/' | relative_url }}">Troubleshooting</a>
10
+ <a href="{{ '/ARCHITECTURE/' | relative_url }}">Architecture</a>
11
+ <a href="{{ '/CHANGELOG/' | relative_url }}">Changelog</a>
12
+ <a href="https://israelmarques1024-dotcom.github.io/karnel-termux/">Live Site</a>
13
+ </nav>
14
+
15
+ {{ content }}
@@ -246,3 +246,37 @@ body {
246
246
  border-top: 1px solid #e1e4e8;
247
247
  padding-top: 1rem;
248
248
  }
249
+
250
+ /* Top navigation bar (injected by _layouts/base.html) */
251
+ .site-nav {
252
+ display: flex;
253
+ flex-wrap: wrap;
254
+ gap: 0.4rem 1.1rem;
255
+ align-items: center;
256
+ padding: 0.7rem 1rem;
257
+ margin-bottom: 1.75rem;
258
+ background: #f3f5f8;
259
+ border: 1px solid #d0d7de;
260
+ border-radius: 10px;
261
+ }
262
+
263
+ .site-nav a {
264
+ color: #0078d4;
265
+ text-decoration: none;
266
+ font-weight: 600;
267
+ font-size: 0.92rem;
268
+ }
269
+
270
+ .site-nav a:hover {
271
+ text-decoration: underline;
272
+ }
273
+
274
+ @media (prefers-color-scheme: dark) {
275
+ .site-nav {
276
+ background: var(--karnel-panel);
277
+ border-color: var(--karnel-border);
278
+ }
279
+ .site-nav a {
280
+ color: var(--karnel-accent);
281
+ }
282
+ }
package/docs/cli/index.md CHANGED
@@ -1,3 +1,9 @@
1
+ ---
2
+ title: CLI Commands
3
+ permalink: /cli/
4
+ layout: base
5
+ ---
6
+
1
7
  # Karnel CLI Reference
2
8
 
3
9
  ```bash
@@ -190,7 +196,7 @@ karnel open <target>
190
196
  ```
191
197
 
192
198
  Opens the official documentation page for a module using
193
- `termux-open-url`. Base URL: `https://karneltermux.vercel.app`
199
+ `termux-open-url`. Base URL: `https://israelmarques1024-dotcom.github.io/karnel-termux`
194
200
 
195
201
  | Target | Opens |
196
202
  |------------------|-------|
@@ -1,3 +1,9 @@
1
+ ---
2
+ title: Doctor System
3
+ permalink: /doctor/
4
+ layout: base
5
+ ---
6
+
1
7
  # Karnel Doctor
2
8
 
3
9
  `karnel doctor` diagnoses the Termux environment, analyzes project code, and
package/docs/index.md CHANGED
@@ -1,20 +1,13 @@
1
- # Karnel Termux Documentation
1
+ ---
2
+ title: Karnel Termux Documentation
3
+ permalink: /
4
+ layout: base
5
+ ---
2
6
 
3
7
  <img class="karnel-logo" src="{{ '/assets/images/karnel-logo.png' | relative_url }}" alt="Karnel Termux">
4
8
 
5
9
  > Modular Dev Environment for Termux — install languages, databases, AI agents, editors, and more with one command
6
10
 
7
- Navigate the docs:
8
-
9
- <ul class="karnel-nav">
10
- <li><a href="./cli/">CLI Commands</a></li>
11
- <li><a href="./doctor/">Doctor System</a></li>
12
- <li><a href="./troubleshooting/">Troubleshooting</a></li>
13
- <li><a href="./ARCHITECTURE/">Architecture</a></li>
14
- <li><a href="./CHANGELOG/">Changelog</a></li>
15
- <li><a href="https://israelmarques1024-dotcom.github.io/karnel-termux/">Live Site</a></li>
16
- </ul>
17
-
18
11
  ## What is Karnel?
19
12
 
20
13
  Karnel Termux transforms your Android device into a complete development workstation.
@@ -1,3 +1,9 @@
1
+ ---
2
+ title: Troubleshooting
3
+ permalink: /troubleshooting/
4
+ layout: base
5
+ ---
6
+
1
7
  # Troubleshooting
2
8
 
3
9
  Common issues when installing, updating, or publishing Karnel Termux.
@@ -55,7 +61,7 @@ The workflow runs `actions/jekyll-build-pages` (from `docs/`, output to
55
61
 
56
62
  If a build fails, open the Actions run for the failing job and read the Jekyll
57
63
  output: the usual causes are invalid `_config.yml` YAML, an SCSS compile error
58
- in `assets/css/style.scss`, or a malformed `{{ }}` Liquid tag. After a
64
+ in `assets/css/style.scss`, or a malformed `{% raw %}{{ }}{% endraw %}` Liquid tag. After a
59
65
  successful deploy, the published site is visible under the repository's
60
66
  **Settings → Pages**.
61
67
 
@@ -1 +1 @@
1
- f3ce43f67dd4d213f0af574d1673e8dbd6c910b9
1
+ ef2964062663afea85983ccb2043d0a8ab6e115e
@@ -121,7 +121,7 @@ _brain_slug_escape() {
121
121
  _brain_update_related() {
122
122
  local file="$1" slug="$2"
123
123
  local tmp
124
- tmp=$(mktemp "${TMPDIR:-/tmp}/karnel-brain.XXXXXX")
124
+ tmp=$(mktemp "${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}/karnel-brain.XXXXXX")
125
125
  local frontmatter_end
126
126
  frontmatter_end=$(awk '/^---$/ {++n} n==2 {print NR; exit}' "$file")
127
127
 
@@ -151,7 +151,7 @@ _brain_update_related() {
151
151
  _brain_remove_related() {
152
152
  local file="$1" slug="$2"
153
153
  local tmp
154
- tmp=$(mktemp "${TMPDIR:-/tmp}/karnel-brain.XXXXXX")
154
+ tmp=$(mktemp "${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}/karnel-brain.XXXXXX")
155
155
  local frontmatter_end
156
156
  frontmatter_end=$(awk '/^---$/ {++n} n==2 {print NR; exit}' "$file")
157
157
 
@@ -64,7 +64,7 @@ _init_lang_tools() {
64
64
  LANG_TOOLS["C/C++:clang_tidy"]="clang-tidy|lint|clang-tidy {} -- -std=c17 2>&1 | head -20|||official"
65
65
 
66
66
  # Java
67
- LANG_TOOLS["Java:javac"]="javac|syntax|javac -d \"${TMPDIR:-/tmp}\" -Xlint:all {} 2>&1 | head -10|||official"
67
+ LANG_TOOLS["Java:javac"]="javac|syntax|javac -d \"${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}\" -Xlint:all {} 2>&1 | head -10|||official"
68
68
 
69
69
  # Docker
70
70
  LANG_TOOLS["Docker:hadolint"]="hadolint|lint|hadolint Dockerfile|||community"
@@ -3,7 +3,7 @@
3
3
  import "@/utils/log"
4
4
  import "@/utils/colors"
5
5
 
6
- OPEN_BASE_URL="https://karneltermux.vercel.app"
6
+ OPEN_BASE_URL="https://israelmarques1024-dotcom.github.io/karnel-termux"
7
7
 
8
8
  open_main() {
9
9
  if [[ $# -eq 0 ]]; then
@@ -737,9 +737,22 @@ pg_schedule() {
737
737
  local escaped_db; printf -v escaped_db '%q' "$db_name"
738
738
  local escaped_path; printf -v escaped_path '%q' "$KARNEL_PATH"
739
739
  local job="$cron_expr KARNEL_PATH=$escaped_path $escaped_path/bin/karnel pg backup $escaped_db >/dev/null 2>&1"
740
- (crontab -l 2>/dev/null | grep -v "karnel pg backup $db_name"; echo "$job") | crontab -
741
- log_success "Backup scheduled successfully ($interval) for database '$db_name'!"
742
- list_item "Ensure cron daemon is running (run: 'crond')"
740
+ local tmpcron
741
+ tmpcron="$(mktemp "${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}/karnel-pg.XXXXXX")" || {
742
+ log_error "Failed to schedule backup for database '$db_name'"
743
+ return 1
744
+ }
745
+ {
746
+ crontab -l 2>/dev/null | grep -vF "karnel pg backup $escaped_db"
747
+ echo "$job"
748
+ } >"$tmpcron"
749
+ if crontab "$tmpcron"; then
750
+ log_success "Backup scheduled successfully ($interval) for database '$db_name'!"
751
+ list_item "Ensure cron daemon is running (run: 'crond')"
752
+ else
753
+ log_error "Failed to schedule backup for database '$db_name'"
754
+ fi
755
+ rm -f "$tmpcron"
743
756
  fi
744
757
  echo
745
758
  }
@@ -47,6 +47,11 @@ show_main() {
47
47
  return 1
48
48
  fi
49
49
 
50
+ if [[ ! "$module" =~ ^[A-Za-z0-9_-]+$ ]]; then
51
+ log_error "Invalid module name: $module"
52
+ return 1
53
+ fi
54
+
50
55
  if [[ "$module" == "backup" ]]; then
51
56
  _show_backup_docs "$tool"
52
57
  return
@@ -226,9 +226,9 @@ _update_try_curl() {
226
226
  command -v curl &>/dev/null || return 1
227
227
 
228
228
  local meta installer sumfile tag
229
- meta=$(mktemp "${TMPDIR:-/tmp}/karnel-meta.XXXXXX") || return 1
230
- installer=$(mktemp "${TMPDIR:-/tmp}/karnel-install.XXXXXX") || { rm -f "$meta"; return 1; }
231
- sumfile=$(mktemp "${TMPDIR:-/tmp}/karnel-sum.XXXXXX") || { rm -f "$meta" "$installer"; return 1; }
229
+ meta=$(mktemp "${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}/karnel-meta.XXXXXX") || return 1
230
+ installer=$(mktemp "${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}/karnel-install.XXXXXX") || { rm -f "$meta"; return 1; }
231
+ sumfile=$(mktemp "${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}/karnel-sum.XXXXXX") || { rm -f "$meta" "$installer"; return 1; }
232
232
 
233
233
  log_info "Trying the official curl installer..."
234
234
 
@@ -3,6 +3,14 @@
3
3
  import "@/utils/log"
4
4
  import "@/utils/version"
5
5
  import "@/utils/colors"
6
+ import "@/utils/install"
7
+
8
+ if ! declare -f safe_extract_tar >/dev/null 2>&1; then
9
+ safe_extract_tar() {
10
+ local archive="$1" outdir="$2" strip_components="${3:-0}"
11
+ tar -xzf "$archive" -C "$outdir" --strip-components="$strip_components"
12
+ }
13
+ fi
6
14
 
7
15
  : "${KARNEL_DATA:=${XDG_DATA_HOME:-$HOME/.local/share}/karnel-data}"
8
16
  : "${KARNEL_CACHE:=${XDG_CACHE_HOME:-$HOME/.cache}/karnel}"
@@ -99,7 +107,7 @@ _cline_install_global_impl() {
99
107
 
100
108
  mkdir -p "$CLINE_DATA_DIR"
101
109
  : >"$CLINE_DATA_DIR/$CLINE_MARKER"
102
- if ! tar -xzf "$tarball" -C "$CLINE_DATA_DIR" &>>"$LOG_FILE"; then
110
+ if ! safe_extract_tar "$tarball" "$CLINE_DATA_DIR" &>>"$LOG_FILE"; then
103
111
  rm -f "$tarball"
104
112
  log_error "Failed to extract cline linux-arm64 binary"
105
113
  return 1
@@ -197,7 +197,7 @@ _goose_download_binary_proot_impl() {
197
197
  return 1
198
198
  fi
199
199
  verify_github_release_asset aaif-goose/goose "v${latest_version}" "$tarball" "$GOOSE_DATA_DIR/$tarball" || return 1
200
- if ! tar -xzf "$GOOSE_DATA_DIR/$tarball" -C "$GOOSE_DATA_DIR" &>>"$LOG_FILE"; then
200
+ if ! extract_tarball "$GOOSE_DATA_DIR/$tarball" "$GOOSE_DATA_DIR" &>>"$LOG_FILE"; then
201
201
  rm -f "$GOOSE_DATA_DIR/$tarball"
202
202
  log_error "Failed to extract Goose CLI"
203
203
  return 1
@@ -3,6 +3,14 @@
3
3
  import "@/utils/log"
4
4
  import "@/utils/colors"
5
5
  import "@/utils/version"
6
+ import "@/utils/install"
7
+
8
+ if ! declare -f safe_extract_tar >/dev/null 2>&1; then
9
+ safe_extract_tar() {
10
+ local archive="$1" outdir="$2" strip_components="${3:-0}"
11
+ tar -xzf "$archive" -C "$outdir" --strip-components="$strip_components"
12
+ }
13
+ fi
6
14
 
7
15
  : "${KARNEL_CACHE:=${XDG_CACHE_HOME:-$HOME/.cache}/karnel}"
8
16
  : "${KARNEL_DATA:=${XDG_DATA_HOME:-$HOME/.local/share}/karnel-data}"
@@ -136,7 +144,7 @@ print(version, download, checksum, sep="\t")
136
144
  fi
137
145
  log_success "Checksum verified"
138
146
 
139
- if tar xzf "$archive" -C "$tmpdir" 2>>"$LOG_FILE"; then
147
+ if safe_extract_tar "$archive" "$tmpdir" 2>>"$LOG_FILE"; then
140
148
  bin_path=$(find "$tmpdir" -name "kiro-cli" -type f -executable 2>/dev/null | head -1)
141
149
  if [[ -z "$bin_path" ]]; then
142
150
  bin_path=$(find "$tmpdir" -name "kiro*" -type f -executable 2>/dev/null | head -1)
@@ -52,7 +52,7 @@ install_supabase() (
52
52
  local checksum_url="${_SUPABASE_RELEASE_URL}/supabase_${_SUPABASE_VERSION}_checksums.txt"
53
53
  local tmp_dir staged_bin marker_staging="" old_bin="" old_marker=""
54
54
  local _kdir="${KARNEL_CACHE:-${XDG_CACHE_HOME:-$HOME/.cache}/karnel}"
55
- mkdir -p "$_kdir" 2>/dev/null || _kdir="${TMPDIR:-/tmp}"
55
+ mkdir -p "$_kdir" 2>/dev/null || _kdir="${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}"
56
56
  tmp_dir=$(mktemp -d "$_kdir/supabase.XXXXXX") || return 1
57
57
  staged_bin=""
58
58
  trap 'rm -rf "$tmp_dir"; [[ -z "$staged_bin" ]] || rm -f "$staged_bin"; [[ -z "$marker_staging" ]] || rm -f "$marker_staging"' EXIT
@@ -519,7 +519,10 @@ _plugin_verify_checksum() {
519
519
  local expected actual
520
520
 
521
521
  expected="$(jq -r '.checksum // empty' "$manifest")" || return 1
522
- [[ -n "$expected" ]] || return 0
522
+ if [[ -z "$expected" ]]; then
523
+ log_error "Plugin '$(jq -r '.name' "$manifest")' has no checksum; refusing install"
524
+ return 1
525
+ fi
523
526
 
524
527
  actual="$(_plugin_payload_checksum "$plugin_root")" || return 1
525
528
  if [[ "$actual" != "$expected" ]]; then
@@ -882,11 +885,15 @@ _plugin_clone_repository() {
882
885
  local repo="$1"
883
886
  local ref="$2"
884
887
  local destination="$3"
888
+ local commit="$4"
885
889
  local source_url="https://github.com/$repo.git"
886
890
 
887
891
  _plugin_require_command git || return 1
888
892
 
889
- if [[ -n "$ref" ]]; then
893
+ if [[ -n "$commit" ]]; then
894
+ git clone "$source_url" "$destination" || return 1
895
+ git -C "$destination" checkout "$commit" --detach || return 1
896
+ elif [[ -n "$ref" ]]; then
890
897
  git clone --depth=1 --branch "$ref" "$source_url" "$destination"
891
898
  else
892
899
  git clone --depth=1 "$source_url" "$destination"
@@ -1083,6 +1090,13 @@ _plugin_stage_and_install() {
1083
1090
  local replace_existing="$7"
1084
1091
  local staging checkout checkout_root candidate candidate_root manifest_name commit installed_ref expected_commit registry_name
1085
1092
 
1093
+ expected_commit=""
1094
+ registry_name=""
1095
+ if [[ -n "$registry_entry" ]]; then
1096
+ expected_commit="$(jq -r '.commit // empty' <<<"$registry_entry")" || return 1
1097
+ registry_name="$(jq -r '.name' <<<"$registry_entry")" || return 1
1098
+ fi
1099
+
1086
1100
  _plugin_prepare_plugins_dir || return 1
1087
1101
  _plugin_validate_repo "$repo" || return 1
1088
1102
  [[ -z "$ref" ]] || _plugin_ref_is_valid "$ref" || {
@@ -1100,7 +1114,7 @@ _plugin_stage_and_install() {
1100
1114
  }
1101
1115
  checkout="$staging/repository"
1102
1116
 
1103
- if ! _plugin_clone_repository "$repo" "$ref" "$checkout"; then
1117
+ if ! _plugin_clone_repository "$repo" "$ref" "$checkout" "$expected_commit"; then
1104
1118
  log_error "Failed to clone plugin repository '$repo'."
1105
1119
  _plugin_cleanup_staging "$staging"
1106
1120
  return 1
@@ -47,7 +47,7 @@ install_amass() (
47
47
  esac
48
48
  url="https://github.com/owasp-amass/amass/releases/download/v${_AMASS_VERSION}/$asset"
49
49
 
50
- tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/amass.XXXXXX") || return 1
50
+ tmpdir=$(mktemp -d "${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}/amass.XXXXXX") || return 1
51
51
  staged_bin=""
52
52
  trap 'rm -rf "$tmpdir"; [ -z "$staged_bin" ] || rm -f "$staged_bin"' EXIT
53
53
  archive="$tmpdir/amass.zip"
@@ -28,7 +28,7 @@ install_burpsuite() (
28
28
 
29
29
  local url tmpdir staged_dir wrapper old_dir wrapper_backup
30
30
  url="https://portswigger.net/burp/releases/download?product=community&type=Jar&version=${_BURP_VERSION}"
31
- tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/burpsuite.XXXXXX") || return 1
31
+ tmpdir=$(mktemp -d "${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}/burpsuite.XXXXXX") || return 1
32
32
  trap 'rm -rf "$tmpdir"' EXIT
33
33
  staged_dir="$tmpdir/data"
34
34
  mkdir -p "$staged_dir" "$PREFIX/bin" "$(dirname "$_BURP_DIR")" || return 1
@@ -26,7 +26,7 @@ _download_ffuf() (
26
26
  *) return 1 ;;
27
27
  esac
28
28
  url="https://github.com/ffuf/ffuf/releases/download/v${_FFUF_VERSION}/$asset"
29
- tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/ffuf.XXXXXX") || return 1
29
+ tmpdir=$(mktemp -d "${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}/ffuf.XXXXXX") || return 1
30
30
  staged_bin=""
31
31
  trap 'rm -rf "$tmpdir"; [ -z "$staged_bin" ] || rm -f "$staged_bin"' EXIT
32
32
  archive="$tmpdir/ffuf.tar.gz"
@@ -19,7 +19,7 @@ _install_gobuster_bin() (
19
19
  x86_64) checksum="871be404ce5f80c96b864586b3caa90f894598d1a8222ae316c19e5f70e04cfc" ;;
20
20
  esac
21
21
  local url="https://github.com/OJ/gobuster/releases/download/v${_GOBUSTER_VERSION}/$asset"
22
- tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/gobuster.XXXXXX") || return 1
22
+ tmpdir=$(mktemp -d "${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}/gobuster.XXXXXX") || return 1
23
23
  staged_bin=""
24
24
  trap 'rm -rf "$tmpdir"; [ -z "$staged_bin" ] || rm -f "$staged_bin"' EXIT
25
25
  archive="$tmpdir/gobuster.tar.gz"
@@ -47,7 +47,7 @@ install_subfinder() (
47
47
  esac
48
48
  url="https://github.com/projectdiscovery/subfinder/releases/download/v${_SUBFINDER_VERSION}/$asset"
49
49
 
50
- tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/subfinder.XXXXXX") || return 1
50
+ tmpdir=$(mktemp -d "${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}/subfinder.XXXXXX") || return 1
51
51
  staged_bin=""
52
52
  trap 'rm -rf "$tmpdir"; [ -z "$staged_bin" ] || rm -f "$staged_bin"' EXIT
53
53
  archive="$tmpdir/subfinder.zip"
@@ -34,7 +34,7 @@ install_zap() (
34
34
 
35
35
  local url="https://github.com/zaproxy/zaproxy/releases/download/v${_ZAP_VERSION}/$ZAP_ASSET"
36
36
 
37
- tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/zap.XXXXXX") || {
37
+ tmpdir=$(mktemp -d "${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}/zap.XXXXXX") || {
38
38
  log_error "Falha ao criar diretório temporário"
39
39
  return 1
40
40
  }
@@ -3,8 +3,13 @@ ZORK_DIR="$HOME/.local/share/karnel-data/zork"
3
3
  if [ ! -f "$ZORK_DIR/zork1.dat" ]; then
4
4
  mkdir -p "$ZORK_DIR"
5
5
  echo "Baixando Zork I..."
6
- curl -sL "https://www.infocom-if.org/downloads/zork1.zip" -o /tmp/zork1.zip
7
- unzip -o /tmp/zork1.zip -d "$ZORK_DIR" 2>/dev/null
8
- rm -f /tmp/zork1.zip
6
+ tmpdir="$(mktemp -d "${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}/zork.XXXXXX")" || exit 1
7
+ curl -fsSL "https://www.infocom-if.org/downloads/zork1.zip" -o "$tmpdir/zork1.zip"
8
+ if unzip -l "$tmpdir/zork1.zip" 2>/dev/null | grep -qE '\.\.[/\\]|^/|[A-Za-z]:\\'; then
9
+ echo "Refusing potentially unsafe Zork archive" >&2
10
+ rm -rf "$tmpdir"; exit 1
11
+ fi
12
+ unzip -o "$tmpdir/zork1.zip" -d "$ZORK_DIR" 2>/dev/null
13
+ rm -rf "$tmpdir"
9
14
  fi
10
15
  exec frotz "$ZORK_DIR/zork1.dat" "$@"
@@ -481,8 +481,10 @@ _agent_exec_to_file() {
481
481
  # ------------------------------------------------------------
482
482
  _agent_cmd_is_write() {
483
483
  local cmd="$1"
484
- # file redirections: >file >>file 2>file 1>>file &>file (excludes fd-to-fd like >&2 and comparisons >=)
485
- if printf '%s\n' "$cmd" | grep -qE '(^|[;&|[:space:]])(>|>>|&>|[0-9]>|[0-9]>>)([^&=]|$)'; then
484
+ # file redirections: >file >>file 2>file 1>>file &>file (also without a
485
+ # preceding space, e.g. echo x>file). Excludes fd-to-fd like >&2 and
486
+ # numeric comparisons >= / =>.
487
+ if printf '%s\n' "$cmd" | grep -qE '(^|[;&|[:space:]]|[A-Za-z0-9])(>|>>|&>)([^&=]|$)'; then
486
488
  return 0
487
489
  fi
488
490
  # command substitution / backticks execute arbitrary code → write
@@ -497,8 +499,14 @@ _agent_cmd_is_write() {
497
499
  if printf '%s\n' "$cmd" | grep -qiE '(^|[;&|[:space:]])(vim|nvim|emacs|ed|ex|vi|nano)[[:space:]]'; then
498
500
  return 0
499
501
  fi
502
+ # interpreters that can execute arbitrary code / spawn processes / modify
503
+ # files even without a trailing redirection or -i flag (sed 'w', perl
504
+ # open(">"), awk system(), env/setsid/nohup running a command, make, xargs)
505
+ if printf '%s\n' "$cmd" | grep -qiE '(^|[;&|[:space:]])(sed|awk|perl|xargs|make|env|nohup|setsid)[[:space:]]'; then
506
+ return 0
507
+ fi
500
508
  # blocklist of commands that write to disk / change state / spawn a shell
501
- printf '%s\n' "$cmd" | grep -qiE '(^|[;&|[:space:]])(rm|rmdir|unlink|mv|cp|mkdir|touch|ln|chmod|chown|chgrp|install|truncate|tee|dd|mkfs|mount|umount|tar|gzip|gunzip|bzip2|xz|zstd|curl|wget|python3|python|node|npm|bun|yarn|pnpm|cargo|go |rustc|git (add|commit|push|pull|merge|rebase|reset|checkout|switch|restore|clean|stash|tag|clone|init|rm|mv)|pkg (install|uninstall|upgrade|reinstall|update)|apt( |-)|apt-get|dpkg|yum|dnf|pacman|brew|pip|pip3|uv|conda|mysql|psql|sqlite3|redis-cli|mongosh|kill|pkill|killall|service|systemctl|halt|reboot|shutdown|sudo|doas|su|pkexec|chroot|bash|sh|dash|zsh|ksh|eval|source|exec|screen|tmux|ssh|scp|sftp|rsync|telnet|nc|ncat|ftp|lftp|rsh|sshpass|socat|crontab|at |iptables|nft|ufw|docker|podman|kubectl|helm)[[:space:]]' && return 0
509
+ printf '%s\n' "$cmd" | grep -qiE '(^|[;&|[:space:]])(rm|rmdir|unlink|mv|cp|mkdir|touch|ln|chmod|chown|chgrp|install|truncate|tee|dd|mkfs|mount|umount|tar|gzip|gunzip|bzip2|xz|zstd|curl|wget|python3|python|node|npm|bun|yarn|pnpm|cargo|go |rustc|git (add|commit|push|pull|merge|rebase|reset|checkout|switch|restore|clean|stash|tag|clone|init|rm|mv|apply|am|worktree|read-tree|update-index|write-tree|checkout-index)|pkg (install|uninstall|upgrade|reinstall|update)|apt( |-)|apt-get|dpkg|yum|dnf|pacman|brew|pip|pip3|uv|conda|mysql|psql|sqlite3|redis-cli|mongosh|kill|pkill|killall|service|systemctl|halt|reboot|shutdown|sudo|doas|su|pkexec|chroot|bash|sh|dash|zsh|ksh|eval|source|exec|screen|tmux|ssh|scp|sftp|rsync|telnet|nc|ncat|ftp|lftp|rsh|sshpass|socat|crontab|at |iptables|nft|ufw|docker|podman|kubectl|helm)[[:space:]]' && return 0
502
510
  return 1
503
511
  }
504
512
 
@@ -898,7 +906,7 @@ agent_exec_loading() {
898
906
  local delay=0.08
899
907
  local tmpfile
900
908
  local _ktmpdir="${KARNEL_CACHE:-${XDG_CACHE_HOME:-$HOME/.cache}/karnel}"
901
- mkdir -p "$_ktmpdir" 2>/dev/null || _ktmpdir="${TMPDIR:-/tmp}"
909
+ mkdir -p "$_ktmpdir" 2>/dev/null || _ktmpdir="${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}"
902
910
  tmpfile="$(mktemp "$_ktmpdir/karnel.XXXXXX" 2>/dev/null)" || tmpfile="$(mktemp 2>/dev/null)"
903
911
 
904
912
  local stty_saved=""
@@ -430,7 +430,7 @@ loading() {
430
430
  local delay=0.08
431
431
  local tmpfile
432
432
  local _ktmpdir="${KARNEL_CACHE:-${XDG_CACHE_HOME:-$HOME/.cache}/karnel}"
433
- mkdir -p "$_ktmpdir" 2>/dev/null || _ktmpdir="${TMPDIR:-/tmp}"
433
+ mkdir -p "$_ktmpdir" 2>/dev/null || _ktmpdir="${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}"
434
434
  tmpfile="$(mktemp "$_ktmpdir/karnel.XXXXXX" 2>/dev/null)" || tmpfile="$(mktemp 2>/dev/null)"
435
435
  local cmd_pid=""
436
436
 
@@ -59,7 +59,7 @@ _run_tool_lifecycle_action() {
59
59
  fi
60
60
  "$uninstall_handler"
61
61
  rc=$?
62
- (( rc == 0 )) || return "$rc"
62
+ (( rc == 0 || rc == 2 )) || return "$rc"
63
63
  "$install_handler"
64
64
  rc=$?
65
65
  if (( rc == 0 && protected )); then
@@ -52,7 +52,7 @@ _spin_capture() {
52
52
  local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
53
53
  local tmp
54
54
  local _ktmpdir="${KARNEL_CACHE:-${XDG_CACHE_HOME:-$HOME/.cache}/karnel}"
55
- mkdir -p "$_ktmpdir" 2>/dev/null || _ktmpdir="${TMPDIR:-/tmp}"
55
+ mkdir -p "$_ktmpdir" 2>/dev/null || _ktmpdir="${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}"
56
56
  tmp=$(mktemp "$_ktmpdir/karnel.XXXXXX" 2>/dev/null) || tmp=$(mktemp 2>/dev/null)
57
57
  local spinner_fd
58
58
  if [ -c /dev/tty ] 2>/dev/null; then
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karnel-termux",
3
- "version": "4.17.9",
3
+ "version": "4.17.10",
4
4
  "description": "Modular Dev Environment for Termux — install languages, databases, AI agents, editors, and more with one command",
5
5
  "bin": {
6
6
  "karnel": "karnel/bin/karnel"