From a308e02b6cc4e8bf0fa6ca1d109d7066049ceb14 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Jul 2026 13:35:32 +0000 Subject: [PATCH 1/3] Initial plan From 08172b68755704b34be3d7bad79536eeeffaa41b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Jul 2026 13:39:37 +0000 Subject: [PATCH 2/3] fix: security and correctness fixes across five scripts - setup_api.sh: Flask API now listens on 127.0.0.1 instead of 0.0.0.0 to avoid unintentional network exposure. - stealth_post.sh: GPG passphrase passed via --passphrase-fd to avoid process-list exposure; FTP credentials moved to a temp netrc file (chmod 600) instead of the curl --user flag; netrc file shred on exit. - pentest_verification.sh: Removed default 'admin'/'admin' GVM credentials (GVM_USER/GVM_PASSWORD are now required); added hostname character validation before interpolating into the XML scan request. - pentest_exploitation.sh: Fixed dry-run side-effect (output file was truncated even in dry-run mode); added missing argument validation for --results and --search-file options. - SharePointManagement.ps1: Fixed SPSite scope bug ($script:SPSite in Add-User); added -ErrorAction Stop to connection calls; added SiteUrl and Template/UserLogin validation in the action switch. - ExchangeOnlineManagement.ps1: Changed return to exit 1 for module-check failures (sets correct non-zero exit code); added try/catch to the 'list' and 'disconnect' actions. --- scripts/linux/pentest_exploitation.sh | 10 +++++++++- scripts/linux/pentest_verification.sh | 10 ++++++++-- scripts/linux/setup_api.sh | 4 +++- scripts/linux/stealth_post.sh | 13 +++++++++---- .../powershell/ExchangeOnlineManagement.ps1 | 16 ++++++++++++---- scripts/powershell/SharePointManagement.ps1 | 19 ++++++++++++++----- 6 files changed, 55 insertions(+), 17 deletions(-) diff --git a/scripts/linux/pentest_exploitation.sh b/scripts/linux/pentest_exploitation.sh index 17157f5..eb237ac 100644 --- a/scripts/linux/pentest_exploitation.sh +++ b/scripts/linux/pentest_exploitation.sh @@ -42,10 +42,16 @@ require_authorization() { while [[ $# -gt 0 ]]; do case "$1" in --results) + if [[ -z "${2:-}" || "${2:-}" == --* ]]; then + echo "Missing value for --results" >&2; exit 1 + fi RESULTS_DIR="$2" shift 2 ;; --search-file) + if [[ -z "${2:-}" || "${2:-}" == --* ]]; then + echo "Missing value for --search-file" >&2; exit 1 + fi SEARCH_FILE="$2" shift 2 ;; @@ -82,7 +88,9 @@ if [[ ! -d "$RESULTS_DIR" ]]; then exit 1 fi -: >"$SEARCH_FILE" +if [[ "$DRY_RUN" != true ]]; then + : >"$SEARCH_FILE" +fi if command -v searchsploit >/dev/null; then SEARCHSPLOIT_AVAILABLE=1 diff --git a/scripts/linux/pentest_verification.sh b/scripts/linux/pentest_verification.sh index b1e4b19..cf8325b 100644 --- a/scripts/linux/pentest_verification.sh +++ b/scripts/linux/pentest_verification.sh @@ -274,9 +274,15 @@ while IFS=$'\t' read -r host safe_host xml; do if command -v gvm-cli >/dev/null; then if [[ "$SKIP_OPENVAS" == true ]]; then record "$host" "openvas" "skipped" "disabled" + elif [[ -z "${GVM_USER:-}" || -z "${GVM_PASSWORD:-}" ]]; then + echo "GVM_USER and GVM_PASSWORD must be set to run OpenVAS scans; skipping." >&2 + record "$host" "openvas" "skipped" "credentials not configured" + elif [[ ! "$host" =~ ^[A-Za-z0-9._:-]+$ ]]; then + echo "Host '$host' contains characters unsafe for XML; skipping OpenVAS." >&2 + record "$host" "openvas" "skipped" "unsafe hostname" else - gvm-cli socket --gmp-username "${GVM_USER:-admin}" \ - --gmp-password "${GVM_PASSWORD:-admin}" \ + gvm-cli socket --gmp-username "$GVM_USER" \ + --gmp-password "$GVM_PASSWORD" \ --xml "" > "$OPENVAS_XML" 2>/dev/null & openvas_pid=$! fi diff --git a/scripts/linux/setup_api.sh b/scripts/linux/setup_api.sh index 93b2d85..a8de5b5 100644 --- a/scripts/linux/setup_api.sh +++ b/scripts/linux/setup_api.sh @@ -109,7 +109,9 @@ def generate(): return jsonify({"response": result.stdout.strip()}) if __name__ == '__main__': - app.run(host='0.0.0.0', port=5000) + # Listen on localhost only; bind to 0.0.0.0 only behind a reverse proxy + # with proper authentication in place. + app.run(host='127.0.0.1', port=5000) APP echo "✅ API créée avec succès : $APP_PATH" diff --git a/scripts/linux/stealth_post.sh b/scripts/linux/stealth_post.sh index 4a73378..c7d1fb1 100644 --- a/scripts/linux/stealth_post.sh +++ b/scripts/linux/stealth_post.sh @@ -94,7 +94,9 @@ done OUT="$(mktemp)" ENC_OUT="$OUT.gpg" -trap 'rm -f "$OUT" "$ENC_OUT"' EXIT +NETRC_FILE="$(mktemp)" +trap 'rm -f "$OUT" "$ENC_OUT" "$NETRC_FILE"' EXIT +chmod 600 "$NETRC_FILE" { echo "[*] $(date '+%Y-%m-%d %H:%M:%S')" @@ -105,16 +107,19 @@ trap 'rm -f "$OUT" "$ENC_OUT"' EXIT df -h } > "$OUT" -if ! gpg --batch --yes --passphrase "$GPG_PASSPHRASE" -c "$OUT"; then +# Pass passphrase via file descriptor to avoid exposure in the process list. +if ! gpg --batch --yes --passphrase-fd 3 -c "$OUT" 3<<<"$GPG_PASSPHRASE"; then echo "gpg encryption failed." >&2 exit 1 fi -if ! curl --ftp-ssl --ssl-reqd -sS -T "$ENC_OUT" --user "$FTP_USER:$FTP_PASS" "ftp://$FTP_HOST/$FTP_PATH" --ftp-create-dirs >/dev/null; then +# Use a netrc file so FTP credentials are not visible in the process list. +printf 'machine %s login %s password %s\n' "$FTP_HOST" "$FTP_USER" "$FTP_PASS" > "$NETRC_FILE" +if ! curl --ftp-ssl --ssl-reqd -sS -T "$ENC_OUT" --netrc-file "$NETRC_FILE" "ftp://$FTP_HOST/$FTP_PATH" --ftp-create-dirs >/dev/null; then echo "FTPS upload failed." >&2 exit 1 fi -shred -u "$OUT" "$ENC_OUT" +shred -u "$OUT" "$ENC_OUT" "$NETRC_FILE" trap - EXIT echo "Encrypted metadata uploaded to ftps://$FTP_HOST/$FTP_PATH" diff --git a/scripts/powershell/ExchangeOnlineManagement.ps1 b/scripts/powershell/ExchangeOnlineManagement.ps1 index 732c4e7..e0193e6 100644 --- a/scripts/powershell/ExchangeOnlineManagement.ps1 +++ b/scripts/powershell/ExchangeOnlineManagement.ps1 @@ -51,14 +51,14 @@ param( # Ensure module is available if (-not (Get-Module -ListAvailable -Name ExchangeOnlineManagement)) { Write-Error 'Exchange Online module is not installed. Install-Module ExchangeOnlineManagement' - return + exit 1 } try { Import-Module ExchangeOnlineManagement -ErrorAction Stop } catch { Write-Error "Failed to import Exchange Online module. $_" - return + exit 1 } switch ($Action.ToLower()) { @@ -71,7 +71,11 @@ switch ($Action.ToLower()) { } } 'list' { - Get-Mailbox + try { + Get-Mailbox -ErrorAction Stop + } catch { + Write-Error "Failed to list mailboxes. $_" + } } 'create' { if (-not $UserPrincipalName) { @@ -154,6 +158,10 @@ switch ($Action.ToLower()) { } } 'disconnect' { - Disconnect-ExchangeOnline -Confirm:$false + try { + Disconnect-ExchangeOnline -Confirm:$false -ErrorAction Stop + } catch { + Write-Error "Failed to disconnect. $_" + } } } diff --git a/scripts/powershell/SharePointManagement.ps1 b/scripts/powershell/SharePointManagement.ps1 index 266c136..2730d28 100644 --- a/scripts/powershell/SharePointManagement.ps1 +++ b/scripts/powershell/SharePointManagement.ps1 @@ -52,12 +52,14 @@ function Connect-SP { ) if ($Mode -eq 'Online') { + if (-not $SiteUrl) { throw 'SiteUrl is required for Online mode.' } Write-Verbose 'Connecting to SharePoint Online...' - Connect-SPOService -Url "https://$((New-Object System.Uri($SiteUrl)).Host)" -Credential $Credential + $adminUrl = "https://$((New-Object System.Uri($SiteUrl)).Host)" + Connect-SPOService -Url $adminUrl -Credential $Credential -ErrorAction Stop } else { Write-Verbose 'Loading SharePoint On-Premise snap-in...' Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue - $script:SPSite = Get-SPSite $SiteUrl + $script:SPSite = Get-SPSite $SiteUrl -ErrorAction Stop } } @@ -92,7 +94,7 @@ function Add-User { if ($Mode -eq 'Online') { Set-SPOUser -Site $SiteUrl -LoginName $UserLogin -IsSiteCollectionAdmin $true } else { - $web = $SPSite.RootWeb + $web = $script:SPSite.RootWeb $user = $web.EnsureUser($UserLogin) $user.Update() } @@ -102,6 +104,13 @@ Connect-SP -Mode $Mode -SiteUrl $SiteUrl -Credential $Credential switch ($Action) { 'ListSites' { List-Sites } - 'CreateSite' { Create-Site -SiteUrl $SiteUrl -Template $Template } - 'AddUser' { Add-User -UserLogin $UserLogin -DisplayName $DisplayName -Email $Email } + 'CreateSite' { + if (-not $SiteUrl) { throw 'SiteUrl is required for CreateSite.' } + if (-not $Template) { throw 'Template is required for CreateSite.' } + Create-Site -SiteUrl $SiteUrl -Template $Template + } + 'AddUser' { + if (-not $UserLogin) { throw 'UserLogin is required for AddUser.' } + Add-User -UserLogin $UserLogin -DisplayName $DisplayName -Email $Email + } } From e55bcee374bd282e51e53e9c272225239efd8d01 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Jul 2026 13:41:05 +0000 Subject: [PATCH 3/3] fix: address code review feedback - pentest_verification.sh: restrict hostname regex to [A-Za-z0-9._-] (remove colon which could enable XML namespace injection) - stealth_post.sh: replace herestring (<<<) with printf pipe for GPG passphrase to avoid potential temp-file creation - SharePointManagement.ps1: add SiteUrl validation for OnPrem mode in Connect-SP, consistent with Online mode validation --- scripts/linux/pentest_verification.sh | 2 +- scripts/linux/stealth_post.sh | 4 ++-- scripts/powershell/SharePointManagement.ps1 | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/linux/pentest_verification.sh b/scripts/linux/pentest_verification.sh index cf8325b..3e64663 100644 --- a/scripts/linux/pentest_verification.sh +++ b/scripts/linux/pentest_verification.sh @@ -277,7 +277,7 @@ while IFS=$'\t' read -r host safe_host xml; do elif [[ -z "${GVM_USER:-}" || -z "${GVM_PASSWORD:-}" ]]; then echo "GVM_USER and GVM_PASSWORD must be set to run OpenVAS scans; skipping." >&2 record "$host" "openvas" "skipped" "credentials not configured" - elif [[ ! "$host" =~ ^[A-Za-z0-9._:-]+$ ]]; then + elif [[ ! "$host" =~ ^[A-Za-z0-9._-]+$ ]]; then echo "Host '$host' contains characters unsafe for XML; skipping OpenVAS." >&2 record "$host" "openvas" "skipped" "unsafe hostname" else diff --git a/scripts/linux/stealth_post.sh b/scripts/linux/stealth_post.sh index c7d1fb1..4d46e7b 100644 --- a/scripts/linux/stealth_post.sh +++ b/scripts/linux/stealth_post.sh @@ -107,8 +107,8 @@ chmod 600 "$NETRC_FILE" df -h } > "$OUT" -# Pass passphrase via file descriptor to avoid exposure in the process list. -if ! gpg --batch --yes --passphrase-fd 3 -c "$OUT" 3<<<"$GPG_PASSPHRASE"; then +# Pass passphrase via pipe to avoid exposure in the process list. +if ! printf '%s' "$GPG_PASSPHRASE" | gpg --batch --yes --passphrase-fd 0 -c "$OUT"; then echo "gpg encryption failed." >&2 exit 1 fi diff --git a/scripts/powershell/SharePointManagement.ps1 b/scripts/powershell/SharePointManagement.ps1 index 2730d28..a4b0f33 100644 --- a/scripts/powershell/SharePointManagement.ps1 +++ b/scripts/powershell/SharePointManagement.ps1 @@ -57,6 +57,7 @@ function Connect-SP { $adminUrl = "https://$((New-Object System.Uri($SiteUrl)).Host)" Connect-SPOService -Url $adminUrl -Credential $Credential -ErrorAction Stop } else { + if (-not $SiteUrl) { throw 'SiteUrl is required for OnPrem mode.' } Write-Verbose 'Loading SharePoint On-Premise snap-in...' Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue $script:SPSite = Get-SPSite $SiteUrl -ErrorAction Stop