Skip to content

1 · Platform attack surface map

แผนที่พื้นผิวโจมตีระดับแพลตฟอร์มหลัง Deep Redo — จัดตาม entry point ที่ attacker แตะได้โดยไม่ต้องมี identity จริง หรือด้วย identity ที่ forge ได้จาก secret ที่หลุด

English: Attack surface map = unauthenticated / weakly authenticated paths + shared-secret forge paths. Every row cites a scorecard ID and file:line.

กลับ index · ถัดไป Top-20 runbook


1.1 How to use this map

ColumnMeaning
SurfaceWhat is exposed (route / decorator / middleware)
Auth realityWhat the code actually enforces
BlastWhat data or privilege is reachable
EvidenceScorecard ID + path

สมมติฐานที่ระบุในหลาย scorecard: WAF/gateway ด้านนอกอาจลดความรุนแรงในทางปฏิบัติ แต่โค้ดยังเป็น auth bypass — ถือว่า Critical จนกว่าจะมีหลักฐาน control ภายนอก (ดู 2way-api/04-scorecard caveat)


1.2 Legacy core — GraphQL + REST side doors

vtrc-api (canonical docs: Vol 3.1.10)

SurfaceAuth realityBlastEvidence
PDF encrypt pipeline execSync(qpdf …)Auth may exist on some routes; password/path enter shell stringRCE on API hostSEC-VTRC-API-01 · vtrc-api/api/src/routes.js:73,120,227,277,355
Default JWT_SECRET = 'secret'Forge JWT if env missingImpersonate any userSEC-VTRC-API-02 · config.js:12
GET …/webdeploymentNo apiKey/JWTTrigger shell binary deploySEC-VTRC-API-03 · routes.js:975-984
GET /file/:id/downloadNo apiKeyConfidential file download if id knownSEC-VTRC-API-04 · routes.js:464
Raw SQL in statLog cronTrusted? / indirectSQLi if untrusted rowsSEC-VTRC-API-07 · lib/controllers/statLog/statLog.js
CORS typo corssAllowlist dead → open originsCSRF / browser abuse assistSEC-VTRC-API-06 · index.js:76-91

ไทย: vtrc-api เป็นจุดรวมของ legacy frontends — command injection + unauth deploy + default JWT เป็น combo ที่ IR ต้อง treat เป็น P0 พร้อม secrets cluster

cu-central-api

SurfaceAuth realityBlastEvidence
/auth/signinbypassPasswordless signin liveAccount takeover without passwordSEC-CU-04 · routes.js (Vol 12.3 / 12.5)
Hardcoded device apiKeysSource = keyDevice-key gate bypassSEC-CU-02 · lib/auth/auth.controller.js
JWT_SECRET empty defaultForge with empty keySession forgeSEC-CU-01 · config.js, jwtToken.js
.env.develop-test in gitUAT secrets in historyUAT DB / JWTSEC-CU-03
ignoreAuth + apiKey onlyNo user JWTResolvers marked ignoreAuth open to anyone with device keySEC-CU-05 · directives/auth.js
LDAP rejectUnauthorized: falseMITM LDAPCredential interceptSEC-CU-06 · activeDirectory.connector.js

centralize-api (NestJS REST)

SurfaceAuth realityBlastEvidence
All controllers @Public()Auth machinery dead (17/17)Full PII employee surfaceCRIT-03, CRIT-04 · Vol 12.3
.env committedDB password + bad SECRET_KEYDB + forgeCRIT-01, CRIT-02

English: NestJS JWT guards exist in the library, but every current route is @Public() — treat centralize-api as an open employee directory unless network ACL is proven.


1.3 Web frontends — token exfil + XSS

RepoSurfaceAuth realityBlastEvidence
vtrc-rc-backoffice.env + CRA inline Stimulsoft MSSQL connSecret in git and browser bundleDirect DB string leakSEC-VTRC-RC-01 · .env; shallow C1/C2 superseded by deep ID
vtrc-rc-backoffice/pathLogin/:token/:refreshTokenToken in URL pathHistory / logs / Referer leakSEC-VTRC-RC-02 · App/index.js:24
vtrc-rc-backofficedangerouslySetInnerHTMLNo sanitizerXSS → steal localStorage tokenSEC-VTRC-RC-04
vtrc-rc-backofficeToken in localStorageXSS-readableSession theftSEC-VTRC-RC-05 · utils/auth.js
vtrc-weblocalStorage tokensXSS-readableSession theftSEC-VTRC-WEB-01 · utils/auth.js
vtrc-webdangerouslySetInnerHTMLNo sanitizerXSSSEC-VTRC-WEB-02
vtrc-webNo CSP / no SRIWeak browser defensesXSS impact↑SEC-VTRC-WEB-03, SEC-VTRC-WEB-04
vtrc-backoffice-newToken in URL cross-originPath segmentsToken leakSEC-BONEW-01 · Login/index.js:93-103 (branch: uat)
recruitment-webAES keys in tracked .env*Bake into CRA bundlePII decryptSEC-RCWEB-01 · .env:2,9, cryptoJs.js:1-32 (branch: prod)
recruitment-webOTP constant 111111Client bypassSoft 2FA skipSEC-RCWEB-03 · header/index.js:230-231

ไทย: Frontend ไม่ใช่แค่ “UI debt” — token-in-URL + XSS + localStorage ทำให้ Critical backend ถูกขยายผ่าน session theft


1.4 2way Platform

2way-api (branch: prod) — scorecard 04

SurfaceAuth realityBlastEvidence
POST …/auth/ backdoor i3adminHardcoded user/pass → JWT admin 48hFull high-privilege sessionSEC-2WAYAPI-01 · auth.service.ts:184-240
SSO AES / SSO password fallbacksEnv missing → literals in sourceDecrypt/forge SSO pathSEC-2WAYAPI-02 · auth.service.ts:20-26
Announces/surveys/complaints SQL concatParams → WHERE stringSQLi (+ many routes @Public)SEC-2WAYAPI-03 · announces.service.ts:164-463
Mutations + LINE @Public()Global JwtAuthGuard skippedWrite workflows / LINE spamSEC-2WAYAPI-04 · announces.controller.ts:45+, line.controller.ts
verifyJwt ignoreExpiration: trueExpired tokens acceptedSession persistence after expireSEC-2WAYAPI-05 · auth.service.ts:31-40
Employees middleware next() onlyOpen proxy to centralizeEmployee PII readSEC-2WAYAPI-08 · employees.controller.ts:33-49
MSSQL encrypt: falseCleartext DB trafficNetwork sniffSEC-2WAYAPI-06 · app.module.ts:39-42
LINE URL http://20.212.116.206:8200Hardcoded HTTP IPMITM / sticky infraSEC-2WAYAPI-07 · line.service.ts:76,86

2way-vtrc-api (branch: prod) — scorecard 04

SurfaceAuth realityBlastEvidence
Bypass "testnaja"Middleware short-circuitAll guarded admin routesSEC-2WAYVTRC-01 · checkbypasstoken.ts:24
LINE middleware same bypassSame stringLIFF endpointsSEC-2WAYVTRC-01b · checkByPassTokenLine.ts:30
POST /2way/getProfileAuth commented outPII by lineIDSEC-2WAYVTRC-02 · getProfile.ts:34-63,79-133
POST /2way/updateIncidentValidator only — no auth middlewareChange incident status unauthSEC-2WAYVTRC-07 · updateIncident.ts:23
Mongo + MSSQL sa in sourceHardcodedDB takeoverSEC-2WAYVTRC-03 / 03b · mongo.config.ts:2-8, env.ts:17-32
SSO creds + AES in loginSSO.tsLiteralsSSO abuseSEC-2WAYVTRC-08 · loginSSO.ts:21-27

2way-line-service

SurfaceAuth realityBlastEvidence
LineController all @Public()No JWTFake LINE events if no signature checkSEC-2WAYLINE-01 · line.controller.ts:13,19,25,31

1.5 Domain microservices

benefit-api (branch: prod) — scorecard 06

SurfaceAuth realityBlastEvidence
.env + SFTP password hardcodeSecrets in gitMSSQL ×3 + JWT + FMIS SFTPSEC-BENEFIT-01 · .env:18,25,32,64; exportpaymentreport.service.ts:5271,5824,6151
Raw SQL empCode = ${…}No paramsSQLi into vtrc schemaSEC-BENEFIT-02 · approvedisaster.service.ts:415-417; payments large ranges
wdHospitals CRUD @Public()No loginMedical claim create/read/updateSEC-BENEFIT-03 · wdhospitals.controller.ts:24-40
Batch import/update @Public()No loginHRMI batch corruptionSEC-BENEFIT-04 · manualBatch.controller.ts:13-34
Upload @Public()No loginMalware store / doc leakSEC-BENEFIT-05 · upload.controller.ts:13-22
/ping-centrail?url=@Public + HTTP pingSSRFSEC-BENEFIT-06 · app.controller.ts:13-16

recruitment-api / ai-recruitment-api / pms-api

SurfaceAuth realityBlastEvidence
recruitment .env + GCP SAIn gitDB + JWT + SMTP + reCAPTCHA + cloudSEC-RECRUIT-01 · .env + vtrc-gcp-sa-key.json (prod)
Dynamic EXEC SP stringUser params concatSQLi on ai connectionSEC-RECRUIT-02 · candidate.repositories.ts:1324-1338
POST /blacklist/import_blacklist @Public()No JWTOpen blacklist importSEC-RECRUIT-03
ai-recruit OpenAI/remove.bg keysIn gitFinancial API abuseSEC-AIRECRUIT-01 · .env:2,5,7,9-10,11
ai-recruit JWT signature onlyNo roleBillable AI for any JWT holderSEC-AIRECRUIT-02 · verifyJWT.js:7-40
GET /budget/getEmployeeSalary @Public()No loginSalary/budget by org unitSEC-PMS-01 · budget.controller.ts:49-53 (uat)
pms .env shared SECRET_KEYIn gitForge JWT across domain clusterSEC-PMS-02 · .env:12,19,26,33,41,45

chat / workflow / common / jobsched / sso

SurfaceAuth realityBlastEvidence
chat raw SQL rooms/tagsQuery string concatSQLiSEC-CHAT-01 · chat.service.ts:103-157, tags.service.ts:55-61
chat .envIn gitMSSQL/Mongo/LINESEC-CHAT-04 · .env:10-11,26,28-29
chat WS + webhookNo guard / no LINE sigSpoof chat / LINESEC-CHAT-02, SEC-CHAT-03
workflow no useGlobalGuardsDecode only + role from sourceDBImpersonate hospital rolesSEC-WORKFLOW-01 · main.ts:9-82, jwt-actor.util.ts:1-4,33-47
workflow .env.example real secretsTrackedAI key + DBSEC-WORKFLOW-02 · .env.example:11,31,44
vtrc-common controllers @Public()Writes openFile/address/bankSEC-COMMON-01
vtrc-common .env + Docker bakesa + SECRET_KEYInstance-wide DBSEC-COMMON-03 · .env:11,17; Dockerfile:19
address SQL concatParamsSQLi shared libSEC-COMMON-02 · address.repository.ts:82-94,117-130
job-scheduler .envsa + RSA secretShared with common/chatSEC-JOBSCHED-01 · .env:9-11,18
job-scheduler cron POSTUnauthenticated outboundTrigger remote crontabSEC-JOBSCHED-02 · incidents.service.ts:20-21 (see jobsched 01/02)
sso-api JWT sign() commentedGuarded endpoints dead after signIn2FA/logout brokenCORR-SSO-01 · app.service.ts:27,143-191,220-223

1.6 Meeting platform

SurfaceAuth realityBlastEvidence
.envdev/.envuat/.envprodSecrets in git (3 envs)JWT/SMTP/DB/apiKeySEC-MTVTRC-01 (branch: prod-meeting-vtrc-api)
GET /meeting/mockuser/oneNo authReal PII hardcodedSEC-MTVTRC-02 · mockuser.ts:29-60, mount app.ts:209-210
Global /meeting/secure/* middlewareEntire block commentedMeetings/PDF/email openSEC-MTVTRC-05 · app.ts:104-120
checkBypassMiddleWareBroken verify (no post; wrong decodeJwt arity)Guard useless if re-enabled as-isSEC-MTVTRC-06 · checkbypass.ts:38-78, jwtdecode.ts:12-19
health-check email / corn-email / static filesNo authSpam + file readSEC-MTVTRC-03, SEC-MTVTRC-07

ไทย: path ชื่อ secure ห้ามเชื่อ — เปิด app.ts ก่อน (scorecard tip)


1.7 Mobile + auxiliary

SurfaceAuth realityBlastEvidence
RSA private PEM in RN bundleClient holds private keyCrypto broken forever for shipped buildsSEC-MOBILE-01 · login.js:16-42; SEC-NEW-01 · RSAKey.ts:11-38
Android keystore passwords in gitSign APK as orgMalicious update signingSEC-MOBILE-02 · build.gradle:174-179
report-log request_*.logPII in gitPDPA exposureSEC-REPORTLOG-01

1.8 ASCII topology — unauth / bypass hotspots

                    [Attacker]

     ┌───────────────────┼───────────────────┐
     ▼                   ▼                   ▼
 pathLogin URL      @Public NestJS      commented Express
 (RC-BO / BO-new)   (benefit/pms/…)     (/meeting/secure/*)
     │                   │                   │
     ▼                   ▼                   ▼
 localStorage XSS    medical/salary      meeting CRUD
 + Stimulsoft .env   /blacklist/batch    + mockuser PII


              shared SECRET_KEY cluster
              (benefit/recruit/ai/pms)


              forge JWT → other domain APIs
 2way-api backdoor i3admin ──► JWT 48h admin
 2way-vtrc "testnaja" ───────► skip middleware
 cu-central signinbypass ────► passwordless user
 centralize @Public 100% ────► employee REST open

1.9 Priority surfaces for IR triage (first 24h)

ถ้ามี incident “มีคนเข้าถึงข้อมูลสวัสดิการ/เงินเดือน/ประชุม” ให้ไล่ตามลำดับนี้ก่อน (อิง Vol 12.5 ROI):

  1. Shared JWT forge from committed SECRET_KEY — Chapter 3
  2. Backdoors still in source — Chapter 4 (SEC-2WAYAPI-01, SEC-2WAYVTRC-01, SEC-CU-04)
  3. @Public() medical/salary/blacklist — Chapter 2 runbook items
  4. Meeting global auth commented — SEC-MTVTRC-05
  5. Token-in-URL logs on reverse proxies — SEC-VTRC-RC-02, SEC-BONEW-01

1.10 Out of scope / UNVERIFIED (explicit)

ItemStatus
Live pentest confirmation on UAT/prodNot claimed here
Whether API gateway adds auth outside codeUNVERIFIED in scorecards
Mobile/OCR deep agents still in flightVol 17.4 — totals not final
Network ACL to 10.188.128.* MSSQLAssumed reachable only if network allows — impact still Critical if secrets leaked

ไป 2 · Top-20 Critical remediation runbook