UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

75 lines 4.71 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NO_LEAKED_CREDENTIALS = void 0; const linter_format_1 = require("../linter-format"); const flowr_search_builder_1 = require("../../search/flowr-search-builder"); const range_1 = require("../../util/range"); const linter_tags_1 = require("../linter-tags"); const vertex_1 = require("../../dataflow/graph/vertex"); const edge_1 = require("../../dataflow/graph/edge"); const r_string_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-string"); const graph_1 = require("../../dataflow/graph/graph"); const defaultCredentialNamePattern = '(?:password|passwd|pwd|secret|api[_.]?key|api[_.]?token|access[_.]?token|auth[_.]?token|bearer[_.]?token|private[_.]?key|credential)'; const defaultCredentialValuePattern = '^(?:AKIA|AIPA|ASIA|AROA)[A-Z0-9]{16}' + // AWS access key IDs (exact 20-char format) '|^gh[psoar]_[A-Za-z0-9_]{10,}' + // GitHub Classic/App/OAuth/Actions tokens '|^github_pat_[A-Za-z0-9_]{10,}' + // GitHub fine-grained PATs '|^glpat-[A-Za-z0-9_-]{20}' + // GitLab Personal Access Tokens (fixed length) '|^xox[baprs]-[0-9A-Za-z]{10,}' + // Slack tokens (xoxb-, xoxp-, xoxa-, xoxr-, xoxs-) '|^sk_(?:live|test)_[A-Za-z0-9]{24}' + // Stripe secret/test keys (length-anchored) '|^rk_live_[A-Za-z0-9]{24}' + // Stripe restricted keys (length-anchored) '|^npm_[A-Za-z0-9]{36}' + // npm access tokens (fixed length) '|^shp(?:at|ss|pa|ca)_[A-Za-z0-9]{32}' + // Shopify Admin/Shared/Private/Custom tokens '|^sk-ant-[A-Za-z0-9_-]{10,}' + // Anthropic API keys '|^sk-proj-[A-Za-z0-9_-]{10,}' + // OpenAI project API keys '|^SG\\.[A-Za-z0-9_-]{22}\\.' + // SendGrid API keys (structured format) '|^-----BEGIN(?:\\s[A-Z]+)* PRIVATE KEY'; // PEM private keys (RSA, EC, DSA, OpenSSH, etc.) exports.NO_LEAKED_CREDENTIALS = { createSearch: () => flowr_search_builder_1.Q.all().filter(vertex_1.VertexType.VariableDefinition), processSearchResult: async (elements, config, data) => { const namePattern = new RegExp(config.credentialNamePattern, 'i'); const valuePattern = new RegExp(config.credentialValuePattern); const normalize = await data.normalize(); const dfg = (await data.dataflow()).graph; let totalChecked = 0; const results = elements.getElements().flatMap(element => { totalChecked++; const name = element.node.lexeme ?? ''; const vertex = dfg.getVertex(element.node.info.id); if (!vertex_1.VariableDefinitionVertex.is(vertex)) { return []; } const nameMatches = namePattern.test(name); for (const [targetId, edge] of dfg.outgoingEdges(element.node.info.id) ?? graph_1.NoEdges) { if (!edge_1.DfEdge.includesType(edge, edge_1.EdgeType.DefinedBy)) { continue; } const targetNode = normalize.idMap.get(targetId); if (targetNode && r_string_1.RString.is(targetNode) && (nameMatches || valuePattern.test(targetNode.content.str))) { return [{ certainty: linter_format_1.LintingResultCertainty.Uncertain, involvedId: element.node.info.id, variableName: name, loc: range_1.SourceLocation.fromNode(element.node) ?? range_1.SourceLocation.invalid() }]; } } return []; }); return { results, '.meta': { totalChecked } }; }, prettyPrint: { [linter_format_1.LintingPrettyPrintContext.Query]: (result) => `Possible hardcoded credential in \`${result.variableName}\` at ${range_1.SourceLocation.format(result.loc)}`, [linter_format_1.LintingPrettyPrintContext.Full]: (result) => `Variable \`${result.variableName}\` at ${range_1.SourceLocation.format(result.loc)} appears to contain a hardcoded credential` }, info: { name: 'No Leaked Credentials', description: 'Detects hardcoded credentials assigned to variables whose names suggest they hold passwords, tokens, or API keys, or whose values match known credential formats (AWS, GitHub, Slack, Stripe, SSH).', tags: [linter_tags_1.LintingRuleTag.Security, linter_tags_1.LintingRuleTag.Experimental, linter_tags_1.LintingRuleTag.Smell], certainty: linter_format_1.LintingRuleCertainty.BestEffort, defaultConfig: { credentialNamePattern: defaultCredentialNamePattern, credentialValuePattern: defaultCredentialValuePattern } } }; //# sourceMappingURL=no-leaked-credentials.js.map