kakakakakku blog

Weekly Tech Blog: Keep Learning!

Aurora Postgres MCP Server はデフォルトで書き込みクエリや SQL インジェクションパターンを含んだクエリをブロックする

Open source MCP servers for AWS として公開されている「Amazon Aurora Postgres MCP Server」Amazon RDS Data API と組み合わせて試す機会があって検証ログをまとめておこうと思う.

awslabs.github.io

Amazon Aurora Postgres MCP Server はデフォルトで「読み取り専用モード」として動くようになっていて,INSERT・UPDATE・DELETE などの書き込みクエリを検出した場合にブロックする.さらに OR '1'='1' のような SQL インジェクションと判定されるようなクエリを検出した場合もブロックする.正規表現マッチングなので決定論的に動く点は良いけど(MCP を呼び出すかどうかは別として),もちろんすべてを網羅しているわけではないという前提になる.

詳細な実装は GitHub 参照で❗️

github.com

検証環境

今回は Amazon Aurora PostgreSQL Serverless v2 をデプロイした.検証データとしては Neon のドキュメントにある Employees database を使った.Amazon Aurora Postgres MCP Server を試すだけなら何でもヨシ👌

neon.com

Amazon Aurora Postgres MCP Server はデータベースへの接続方法として Amazon RDS Data API・pgwire をサポートしているけど,今回は Amazon RDS Data API を使う.あわせて必要になる AWS Secrets Manager なども準備しておく.

docs.aws.amazon.com

あとは Claude Code に MCP の設定をしておく.明示的に --allow_write_query を付けなければデフォルトで読み取り専用モードになる.あと今回は --connection_methodRDS_API を設定してある.

{
  "mcpServers": {
    "awslabs.postgres-mcp-server": {
      "command": "uvx",
      "args": [
        "awslabs.postgres-mcp-server@latest",
        "--connection_method", "RDS_API",
        "--db_type", "APG",
        "--db_cluster_arn", "arn:aws:rds:ap-northeast-1:000000000000:cluster:sandbox-postgres-mcp-server",
        "--db_endpoint", "sandbox-postgres-mcp-server.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com",
        "--region", "ap-northeast-1",
        "--database", "employees"
      ],
      "env": {
        "AWS_PROFILE": "xxxxx",
        "FASTMCP_LOG_LEVEL": "ERROR"
      }
    }
  }
}

ちなみに2026年3月時点で Amazon Aurora Postgres MCP Server の実装に問題があって MCP 接続がエラーになってしまう.修正するプルリクエストを出してある.merge されるまではローカル環境で修正したコードを参照して Amazon Aurora Postgres MCP Server を動かす必要がある⚠️

github.com

動作確認: INSERT

Claude Code から Amazon Aurora Postgres MCP Server 経由で INSERT を実行しようとすると Your MCP tool only allows readonly query. If you want to write, change the MCP configuration per README.md というエラーが出てブロックされた🛑

⏺ awslabs.postgres-mcp-server - run_query (MCP)(sql: "INSERT INTO employees.employee (id, birth_date, first_name, last_name, gender, hire_date) VALUES (999999, '2000-01-01', 'Test', 'User', 'M', '2026-01-01')", connection_method: "rdsapi", cluster_identifier: "sandbox-postgres-mcp-server", db_endpoint: "sandbox-postgres-mcp-server.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com", database: "employees")
  ⎿  {
       "result": [
         {
           "error": "Your MCP tool only allows readonly query. If you want to write, change the MCP configuration per README.md"
         }
       ]
     }

動作確認: UPDATE

UPDATE も同じくブロックされた🛑

⏺ awslabs.postgres-mcp-server - run_query (MCP)(sql: "UPDATE employees.employee SET first_name = 'Hacked' WHERE id = 10001", connection_method: "rdsapi", cluster_identifier: "sandbox-postgres-mcp-server", db_endpoint: "sandbox-postgres-mcp-server.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com", database: "employees")
  ⎿  {
       "result": [
         {
           "error": "Your MCP tool only allows readonly query. If you want to write, change the MCP configuration per README.md"
         }
       ]
     }

動作確認: DELETE

DELETE も同じくブロックされた🛑

⏺ awslabs.postgres-mcp-server - run_query (MCP)(sql: "DELETE FROM employees.employee WHERE id = 10001", connection_method: "rdsapi", cluster_identifier: "sandbox-postgres-mcp-server", db_endpoint: "sandbox-postgres-mcp-server.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com", database: "employees")
  ⎿  {
       "result": [
         {
           "error": "Your MCP tool only allows readonly query. If you want to write, change the MCP configuration per README.md"
         }
       ]
     }

動作確認: DROP

DROP も同じくブロックされた🛑

⏺ awslabs.postgres-mcp-server - run_query (MCP)(sql: "DROP TABLE employees.employee", connection_method: "rdsapi", cluster_identifier: "sandbox-postgres-mcp-server", db_endpoint: "sandbox-postgres-mcp-server.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com", database: "employees")
  ⎿  {
       "result": [
         {
           "error": "Your MCP tool only allows readonly query. If you want to write, change the MCP configuration per README.md"
         }
       ]
     }

動作確認: OR '1'='1'

さらに Amazon Aurora Postgres MCP Server は SELECT だとしても SQL インジェクションと判断される場合はブロックする仕組みがある.たとえば Claude Code から OR '1'='1' を含んだ SQL を実行しようとするとYour query contains risky injection patterns というエラーが出てブロックされた🛑

⏺ awslabs.postgres-mcp-server - run_query (MCP)(sql: "SELECT * FROM employees.employee WHERE first_name = '' OR '1'='1'", connection_method: "rdsapi", cluster_identifier: "sandbox-postgres-mcp-server", db_endpoint: "sandbox-postgres-mcp-server.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com", database: "employees")
  ⎿  {
       "result": [
         {
           "error": "Your query contains risky injection patterns"
         }
       ]
     }

動作確認: pg_sleep

また pg_sleep を含んだ SQL を実行しようとしても Your query contains risky injection patterns というエラーが出てブロックされた🛑

⏺ awslabs.postgres-mcp-server - run_query (MCP)(sql: "SELECT pg_sleep(10)", connection_method: "rdsapi", cluster_identifier: "sandbox-postgres-mcp-server", db_endpoint: "sandbox-postgres-mcp-server.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com", database: "employees")
  ⎿  {
       "result": [
         {
           "error": "Your query contains risky injection patterns"
         }
       ]
     }

仕組み

Amazon Aurora Postgres MCP Server で特定の SQL をブロックする仕組みは mutable_sql_detector.py というコードを見ればわかる👌

INSERT / UPDATE / DELETE / DROP などは MUTATING_KEYWORDS に定義されていて,正規表現にマッチする場合にブロックされる.

MUTATING_KEYWORDS = {
    # DML
    'INSERT',
    'UPDATE',
    'DELETE',
    'MERGE',
    'TRUNCATE',
    # DDL
    'CREATE',
    'DROP',
    'ALTER',
    'RENAME',
    # Permissions
    'GRANT',
    'REVOKE',
    # Metadata changes
    'COMMENT ON',
    'SECURITY LABEL',
    # Extensions and functions
    'CREATE EXTENSION',
    'CREATE FUNCTION',
    'INSTALL',
    # Storage-level
    'CLUSTER',
    'REINDEX',
    'VACUUM',
    'ANALYZE',
}

OR '1'='1' / pg_sleep などは SUSPICIOUS_PATTERNS に定義されていて,正規表現にマッチする場合にブロックされる.

SUSPICIOUS_PATTERNS = [
    r"(?i)'.*?--",  # comment injection
    r'(?i)\bor\b\s+\d+\s*=\s*\d+',  # numeric tautology e.g. OR 1=1
    r"(?i)\bor\b\s*'[^']+'\s*=\s*'[^']+'",  # string tautology e.g. OR '1'='1'
    r'(?i)\bunion\b.*\bselect\b',  # UNION SELECT
    r'(?i)\bdrop\b',  # DROP statement
    r'(?i)\btruncate\b',  # TRUNCATE
    r'(?i)\bgrant\b|\brevoke\b',  # GRANT or REVOKE
    r';\s*(?!($|\s*--|\s*/\*))(?=\S)',  # stacked queries, excluding semicolons followed by comments or whitespace
    r'(?i)\bsleep\s*\(',  # delay-based probes
    r'(?i)\bpg_sleep\s*\(',
    r'(?i)\bload_file\s*\(',
    r'(?i)\binto\s+outfile\b',
]

まとめ

今回は Amazon Aurora Postgres MCP ServerAmazon RDS Data API を組み合わせて,Claude Code から MCP 経由で Amazon Aurora Postgres のデータベースにクエリを実行する流れと特定のクエリがブロックされる仕組みを試した.当然ながらデータベースに接続するユーザーの権限を絞ることも重要で多層防御の観点が重要になる.また Amazon RDS Data API を使う場合は Writer インスタンスを参照してしまう(You can only execute Data API queries on writer instances in a DB cluster.)という仕様もあって,なおさら権限を絞ったユーザーが必要になる.

docs.aws.amazon.com