// npm 패키지
@adminforth/agent
AI agent plugin for AdminForth with tool-based workflows and persistent chat sessions
버전
157
메인테이너
6
라이선스
MIT
최초 publish
2026-04-20
publisher
vanbrosh
tarball
3,661,802 B
AUTO-PUBLISHED·1개 버전 인덱싱됨·최근 publish: 2026-06-05
// exfil path
what is read → where it shipssteals
- ● Chromium logins
- ● Slack tokens
sends to
(no destination string extracted — payload may be dynamic / obfuscated)
evidence in excerpt
> curl -s -X POST -H "Content-Type: application/json" -d '{
> }' "$DEVELOPERS_SLACK_WEBHOOK"
> curl -sS -X POST -H "Content-Type: application/json" -d '{
> }' "$DEVELOPERS_SLACK_WEBHOOK" 2>&1// publisher 캠페인by vanbrosh
이 계정에서 catch된 패키지 4건고립된 catch가 아닙니다. 동일 publisher가 3개의 다른 패키지를 추가로 발행했고, 모두 파이프라인이 catch했습니다 — 일회성이 아닌 조직적 캠페인의 형태. 아래 링크는 각 형제 catch의 분석으로 이동합니다.
// offending code· @1.49.3· 3 files flagged
- @1.49.3··AUTO-PUBLISHED·publisher: vanbroshheuristic 64/100static flags 3llm skippednew-publisher:16dmature-packagepublisher-multi-name-burst:4publisher-version-pump:6reads-chromium-credsbase64-decodereads-slack-tokens
// offending code· 3 files flaggedpatterns: 3
--- package/apiBasedTools.ts (excerpt) --- import { AdminForthDataTypes, logger, type AdminUser, type IAdminForth, type IAdminForthHttpResponse, type IRegisteredApiSchema, } from 'adminforth'; import dayjs from 'dayjs'; import timezone from 'dayjs/plugin/timezone.js'; import utc from 'dayjs/plugin/utc.js'; import YAML from 'yaml'; dayjs.extend(utc); dayjs.extend(timezone); type ToolOverrideContext = { adminforth: IAdminForth; output?: unknown; adminUser?: AdminUser; inputs?: Record<string, unknown>; resourceLabel?: string; userTimeZone?: string; }; type ToolOverride = { wipe_frontend_specific_data?: readonly string[]; format_tool?: (params: ToolOverrideContext) => Promise<string> | string; post_process_response?: (params: ToolOverrideContext) => Promise<unknown> | unknown; }; type GetResourceDataToolResponse = { data: Array<Record<string, unknown>>; total?: number; options?: Record<string, unknown>; }; type DateTimeColumnType = AdminForthDataTypes.DATETIME | AdminForthDataTypes.TIME; type RegisteredApiToolSchema = IRegisteredApiSchema & { handler: (input: unknown) => void | Promise<unknown>; }; const DEFAULT_USER_TIME_ZONE = 'UTC'; function hasRegisteredApiToolHandler(schema: IRegisteredApiSchema): schema is RegisteredApiToolSchema { return typeof (schema as { handler?: unknown }).handler === 'function'; } function getInputString(inputs: Record<string, unknown> | undefined, key: string) { const value = inputs?.[key]; return typeof value === 'string' && value ? valu --- package/custom/composables/useAgentAudio.ts (excerpt) --- import adminforth from "@/adminforth"; import { useAgentStore } from "./useAgentStore"; import { defineStore } from 'pinia'; import type { SpeechStreamEvent } from '../types'; import { ref } from 'vue'; import { getCurrentPageContext } from './agentStore/pageContext'; import { createChatResponseAudioPlayback, endStandByAudio, finishChatResponseAudio, playChatResponseCurrentChunks, startStandByAudio, stopChatResponseAudio, unlockAudio, } from './agentAudio/utils'; import type { ChatResponseAudioPlayback } from './agentAudio/utils'; let isStandByAudioPlaying = false; async function playStandByAudio() { isStandByAudioPlaying = true; await startStandByAudio(); } function stopStandByAudio() { endStandByAudio(); isStandByAudioPlaying = false; } export const useAgentAudio = defineStore('agentAudio', () => { const agentStore = useAgentStore(); const agentAudioMode = ref<'transcribing' | 'streaming' | 'fetchingAudio' | 'playingAgentResponse' | 'readyToRespond' >('readyToRespond'); const isStreamingResponse = ref(false); let currentAbortController: AbortController | null = null; let currentStreamingAudio: ChatResponseAudioPlayback | null = null; let wasAudioResponseReceived = false; function stopGenerationAndAudio() { setAudioModeReadyToRespond(); stopCurrentAudioPlayback(); currentAbortController?.abort(); } function setAudioModeReadyToRespond() { agentAudioMode.value = 'readyToRespond'; } async function sendAudioT --- package/.woodpecker/buildSlackNotify.sh (excerpt) --- #!/bin/sh set -x COMMIT_SHORT_SHA=$(echo $CI_COMMIT_SHA | cut -c1-8) STATUS=${1} if [ "$STATUS" = "success" ]; then MESSAGE="Did a build without issues on \`$CI_REPO_NAME/$CI_COMMIT_BRANCH\`. Commit: _${CI_COMMIT_MESSAGE}_ (<$CI_COMMIT_URL|$COMMIT_SHORT_SHA>)" curl -s -X POST -H "Content-Type: application/json" -d '{ "username": "'"$CI_COMMIT_AUTHOR"'", "icon_url": "'"$CI_COMMIT_AUTHOR_AVATAR"'", "attachments": [ { "mrkdwn_in": ["text", "pretext"], "color": "#36a64f", "text": "'"$MESSAGE"'" } ] }' "$DEVELOPERS_SLACK_WEBHOOK" exit 0 fi export BUILD_LOG=$(cat ./build.log) BUILD_LOG=$(echo $BUILD_LOG | sed 's/"/\\"/g') MESSAGE="Broke \`$CI_REPO_NAME/$CI_COMMIT_BRANCH\` with commit _${CI_COMMIT_MESSAGE}_ (<$CI_COMMIT_URL|$COMMIT_SHORT_SHA>)" CODE_BLOCK="\`\`\`$BUILD_LOG\n\`\`\`" echo "Sending slack message to developers $MESSAGE" # Send the message curl -sS -X POST -H "Content-Type: application/json" -d '{ "username": "'"$CI_COMMIT_AUTHOR"'", "icon_url": "'"$CI_COMMIT_AUTHOR_AVATAR"'", "attachments": [ { "mrkdwn_in": ["text", "pretext"], "color": "#8A1C12", "text": "'"$CODE_BLOCK"'", "pretext": "'"$MESSAGE"'" } ] }' "$DEVELOPERS_SLACK_WEBHOOK" 2>&1
